থাম্বনেইল ক্লিক করলে মডালে বড় ইমেজ দেখানো (Tabbed/Modal Image Gallery)
ছোট থাম্বনেইল ইমেজের গ্রিড, যেগুলো ক্লিক করলে একটি মডাল (Modal) খুলে বড় আকারে ইমেজ দেখায়। এটি লাইটবক্স (Lightbox) স্টাইল গ্যালারির সিম্পল ভার্সন।
পূর্ণ কোড উদাহরণ
<!DOCTYPE html>
<html lang="bn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ট্যাবড ইমেজ গ্যালারি</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; padding: 20px; background: #f5f5f5; }
h1 { text-align: center; margin-bottom: 30px; color: #333; }
/* থাম্বনেইল গ্রিড */
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 16px;
max-width: 900px;
margin: 0 auto;
}
.thumb {
width: 100%;
aspect-ratio: 4/3;
object-fit: cover;
border-radius: 8px;
cursor: zoom-in;
transition: transform 0.2s, box-shadow 0.2s;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.thumb:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0,0,0,0.15);
}
.thumb:focus { outline: 3px solid #4f46e5; outline-offset: 2px; }
/* মডাল (লুকানো) */
.modal {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.9);
backdrop-filter: blur(4px);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
padding: 20px;
}
.modal.open {
opacity: 1;
visibility: visible;
}
/* মডাল ইমেজ */
.modal-img {
max-width: 100%;
max-height: 90vh;
object-fit: contain;
border-radius: 4px;
box-shadow: 0 0 40px rgba(0,0,0,0.5);
transform: scale(0.9);
transition: transform 0.3s ease;
}
.modal.open .modal-img { transform: scale(1); }
/* ক্যাপশন */
.modal-caption {
position: absolute;
bottom: -50px;
left: 50%;
transform: translateX(-50%);
color: white;
font-size: 16px;
text-align: center;
max-width: 90%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* ক্লোজ বাটন */
.modal-close {
position: absolute;
top: 20px;
right: 30px;
width: 48px;
height: 48px;
background: rgba(255,255,255,0.1);
border: none;
border-radius: 50%;
color: white;
font-size: 28px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s, transform 0.2s;
line-height: 1;
}
.modal-close:hover { background: rgba(255,255,255,0.2); transform: rotate(90deg); }
.modal-close:focus { outline: 3px solid #4f46e5; outline-offset: 3px; }
/* নেভিগেশন অ্যারো (অপশনাল) */
.modal-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 56px;
height: 56px;
background: rgba(255,255,255,0.1);
border: none;
border-radius: 50%;
color: white;
font-size: 24px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
opacity: 0.7;
}
.modal-nav:hover { opacity: 1; background: rgba(255,255,255,0.2); }
.modal-prev { left: 20px; }
.modal-next { right: 20px; }
@media (max-width: 600px) {
.modal-nav { width: 44px; height: 44px; font-size: 20px; }
.modal-prev { left: 10px; }
.modal-next { right: 10px; }
}
</style>
</head>
<body>
<h1>ট্যাবড ইমেজ গ্যালারি</h1>
<div class="gallery" id="gallery">
<img class="thumb" src="https://picsum.photos/id/1015/400/300.jpg" alt="পাহাড় এবং নদী" data-full="https://picsum.photos/id/1015/1200/900.jpg">
<img class="thumb" src="https://picsum.photos/id/1016/400/300.jpg" alt="জঙ্গল পথ" data-full="https://picsum.photos/id/1016/1200/900.jpg">
<img class="thumb" src="https://picsum.photos/id/1018/400/300.jpg" alt="সানসেট বীচ" data-full="https://picsum.photos/id/1018/1200/900.jpg">
<img class="thumb" src="https://picsum.photos/id/1020/400/300.jpg" alt="শহরের স্কাইলাইন" data-full="https://picsum.photos/id/1020/1200/900.jpg">
<img class="thumb" src="https://picsum.photos/id/1021/400/300.jpg" alt="বনের ভিতর" data-full="https://picsum.photos/id/1021/1200/900.jpg">
<img class="thumb" src="https://picsum.photos/id/1022/400/300.jpg" alt="পাহাড়ি ঝরনা" data-full="https://picsum.photos/id/1022/1200/900.jpg">
</div>
<!-- মডাল -->
<div class="modal" id="modal" role="dialog" aria-modal="true" aria-label="ইমেজ ভিউয়ার">
<button class="modal-close" id="modalClose" aria-label="বন্ধ করুন">×</button>
<button class="modal-nav modal-prev" id="modalPrev" aria-label="পূর্বের ছবি">‹</button>
<img class="modal-img" id="modalImg" src="" alt="">
<div class="modal-caption" id="modalCaption"></div>
<button class="modal-nav modal-next" id="modalNext" aria-label="পরবর্তী ছবি">›</button>
</div>
<script>
const gallery = document.getElementById('gallery');
const modal = document.getElementById('modal');
const modalImg = document.getElementById('modalImg');
const modalCaption = document.getElementById('modalCaption');
const closeBtn = document.getElementById('modalClose');
const prevBtn = document.getElementById('modalPrev');
const nextBtn = document.getElementById('modalNext');
const thumbs = [...gallery.querySelectorAll('.thumb')];
let currentIndex = 0;
// মডাল খুলুন
function openModal(index) {
currentIndex = index;
const thumb = thumbs[currentIndex];
modalImg.src = thumb.dataset.full || thumb.src;
modalImg.alt = thumb.alt;
modalCaption.textContent = thumb.alt;
modal.classList.add('open');
document.body.style.overflow = 'hidden';
updateNavButtons();
}
// মডাল বন্ধ
function closeModal() {
modal.classList.remove('open');
document.body.style.overflow = '';
// ছবি আনলোড করুন মেমরি বাঁচাতে (ঐচ্ছিক)
// modalImg.src = '';
}
// নেভিগেশন আপডেট
function updateNavButtons() {
prevBtn.style.display = currentIndex === 0 ? 'none' : 'flex';
nextBtn.style.display = currentIndex === thumbs.length - 1 ? 'none' : 'flex';
}
// পরবর্তী/পূর্বের ছবি
function navigate(dir) {
const newIndex = currentIndex + dir;
if (newIndex >= 0 && newIndex < thumbs.length) {
openModal(newIndex);
}
}
// ইভেন্ট লিসেনার
thumbs.forEach((thumb, index) => {
thumb.addEventListener('click', () => openModal(index));
thumb.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
openModal(index);
}
});
});
closeBtn.addEventListener('click', closeModal);
prevBtn.addEventListener('click', () => navigate(-1));
nextBtn.addEventListener('click', () => navigate(1));
// ব্যাকড্রপ ক্লিক
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal();
});
// কীবোর্ড নেভিগেশন
document.addEventListener('keydown', (e) => {
if (!modal.classList.contains('open')) return;
if (e.key === 'Escape') closeModal();
if (e.key === 'ArrowLeft') navigate(-1);
if (e.key === 'ArrowRight') navigate(1);
});
// টাচ സ്വাইপ (মোবাইল)
let touchStartX = 0;
modal.addEventListener('touchstart', (e) => { touchStartX = e.touches[0].clientX; }, { passive: true });
modal.addEventListener('touchend', (e) => {
const touchEndX = e.changedTouches[0].clientX;
const diff = touchStartX - touchEndX;
if (Math.abs(diff) > 50) {
navigate(diff > 0 ? 1 : -1);
}
});
</script>
</body>
</html>
মূল ফিচারসমূহ
- রেসপন্সিভ গ্রিড: `grid-template-columns: repeat(auto-fill, minmax(200px, 1fr))` — স্ক্রিন সাইজ অনুযায়ী কলাম অটো-অ্যাডজাস্ট।
- হাই-রেজ ইমেজ: থাম্বনেইলে `data-full` অ্যাট্রিবিউটে বড় ইমেজের URL — মডালে লোড হয়।
- মডাল অ্যানিমেশন: ফেড-ইন + স্কেল অ্যানিমেশন।
- কীবোর্ড নেভিগেশন: Arrow Left/Right, ESC, Enter/Space।
- টাচ স্বাইপ: মোবাইলে বাম/ডান স্বাইপ করলে ছবি পরিবর্তন।
- অ্যাক্সেসিবিলিটি: `role="dialog"`, `aria-modal`, `aria-label`, ফোকাস ম্যানেজমেন্ট।
- প্রিভ/নেক্স্ট বাটন: প্রথম/শেষ ছবিতে অটোমেটিক লুকানো।
উন্নত করুন (প্রো টিপস)
| ফিচার | কীভাবে যোগ করবেন |
|---|---|
| লেজি লোডিং | থাম্বনেইলে `loading="lazy"`, মডালে শুধু খোলার সময় লোড |
| প্রিলোড নেক্স্ট ইমেজ | `new Image().src = thumbs[currentIndex+1]?.dataset.full` |
| ক্যাপশন আন্ডার ইমেজ | `.modal-caption` কে `bottom: 10px` দিয়ে ইমেজের নিচে আনুন |
| ফুলস্ক্রিন API | `modalImg.requestFullscreen()` ডাবল ক্লিকে |
| URL হ্যাশ রাউটিং | `location.hash = 'img-' + index` দিয়ে ডায়রেক্ট লিংক শেয়ার |
| অনিমেশন লাইব্রেরি | Framer Motion, GSAP ব্যবহার করে উন্নত অ্যানিমেশন |
এই গ্যালারিটি ই-কমার্স, পোর্টফোলিও, ব্লগ — যেকোনো জায়গায় ব্যবহার করা যায়।