Image Gallery Using HTML CSS & JavaScript

image gallery html, css javascript
Code Snippet:image gallery html, css javascript
Author: W3Frontend
Published: 3 months ago
Last Updated: August 21, 2025
Downloads: 94
License: MIT
Edit Code online: View on CodePen
Read More

This tutorial will guide you through creating an interactive image gallery using HTML, CSS, and JavaScript. This image gallery will be responsive and feature filtering, searching, and a lightbox for viewing images in detail. You’ll learn how to structure your HTML for optimal organization, style your gallery with CSS for a visually appealing design, and add dynamic functionality with JavaScript for an enhanced user experience. The target audience is beginners to intermediate web developers.

Step 1: Setting up the HTML Structure

Creating the Gallery Container

This section lays the foundation for your image gallery. We’ll create the main container, a header for titles, controls for filtering and viewing, and the grid where images will be displayed. A lightbox is also included for a larger view.

<div class="gallery-container">
        <div class="gallery-header">
            <h1 class="gallery-title">Premium Gallery</h1>
            <p class="gallery-subtitle">Explore our curated collection of stunning visuals</p>
        </div>

        <div class="gallery-controls">
            <button class="filter-btn active" data-filter="all">All</button>
            <button class="filter-btn" data-filter="nature">Nature</button>
            <button class="filter-btn" data-filter="architecture">Architecture</button>
            <button class="filter-btn" data-filter="abstract">Abstract</button>
            <input type="text" class="search-box" placeholder="Search images...">
            <button class="view-btn active" data-view="grid">Grid View</button>
            <button class="view-btn" data-view="list">List View</button>
        </div>

        <div class="gallery-grid" id="gallery">
            <!-- Images will be dynamically loaded here -->
        </div>
    </div>

    <!-- Lightbox -->
    <div class="lightbox" id="lightbox">
        <div class="lightbox-content">
            <div class="zoom-controls">
                <button class="zoom-btn" id="zoomIn">+</button>
                <button class="zoom-btn" id="zoomOut">-</button>
                <button class="zoom-btn" id="zoomReset">⌂</button>
            </div>
            <img class="lightbox-image" id="lightboxImage" alt="">
            <button class="lightbox-nav lightbox-prev" id="prevBtn">‹</button>
            <button class="lightbox-nav lightbox-next" id="nextBtn">›</button>
            <button class="lightbox-close" id="closeBtn">×</button>
            <div class="lightbox-info" id="lightboxInfo">
                <h3 id="lightboxTitle"></h3>
                <p id="lightboxDescription"></p>
            </div>
        </div>
    </div>

Step 2: Styling with CSS

Here, we’ll add CSS styles to make the gallery visually appealing and responsive. The styles cover various elements, from the overall layout to individual image containers and the lightbox.

* {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .gallery-container {
            max-width: 1200px;
            margin: 0 auto;
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            border-radius: 20px;
            padding: 30px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
        }

        .gallery-header {
            text-align: center;
            margin-bottom: 40px;
        }

        .gallery-title {
            font-size: 2.5rem;
            font-weight: 700;
            background: linear-gradient(45deg, #667eea, #764ba2);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
            margin-bottom: 10px;
        }

        .gallery-subtitle {
            color: #666;
            font-size: 1.1rem;
        }

        .gallery-controls {
            display: flex;
            justify-content: center;
            align-items: center;
            gap: 15px;
            margin-bottom: 30px;
            flex-wrap: wrap;
        }

        .filter-btn, .view-btn {
            padding: 10px 20px;
            border: 2px solid #667eea;
            background: transparent;
            color: #667eea;
            border-radius: 25px;
            cursor: pointer;
            transition: all 0.3s ease;
            font-weight: 500;
        }

        .filter-btn:hover, .view-btn:hover,
        .filter-btn.active, .view-btn.active {
            background: #667eea;
            color: white;
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
        }

        .search-box {
            padding: 12px 20px;
            border: 2px solid #ddd;
            border-radius: 25px;
            outline: none;
            font-size: 16px;
            width: 250px;
            transition: all 0.3s ease;
        }

        .search-box:focus {
            border-color: #667eea;
            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
        }

        .gallery-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }

        .gallery-grid.list-view {
            grid-template-columns: 1fr;
        }

        .gallery-item {
            position: relative;
            border-radius: 15px;
            overflow: hidden;
            cursor: pointer;
            transition: all 0.3s ease;
            background: white;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
        }

        .gallery-item:hover {
            transform: translateY(-10px) scale(1.02);
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
        }

        .gallery-item.hidden {
            display: none;
        }

        .gallery-image {
            width: 100%;
            height: 250px;
            object-fit: cover;
            transition: all 0.3s ease;
        }

        .gallery-grid.list-view .gallery-image {
            height: 200px;
        }

        .gallery-overlay {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(45deg, rgba(102, 126, 234, 0.8), rgba(118, 75, 162, 0.8));
            display: flex;
            align-items: center;
            justify-content: center;
            opacity: 0;
            transition: all 0.3s ease;
        }

        .gallery-item:hover .gallery-overlay {
            opacity: 1;
        }

        .gallery-info {
            padding: 20px;
        }

        .gallery-info h3 {
            font-size: 1.2rem;
            margin-bottom: 8px;
            color: #333;
        }

        .gallery-info p {
            color: #666;
            font-size: 0.9rem;
            line-height: 1.5;
        }

        .gallery-tag {
            display: inline-block;
            background: #f0f0f0;
            padding: 4px 8px;
            border-radius: 12px;
            font-size: 0.8rem;
            margin: 5px 5px 0 0;
            color: #555;
        }

        .overlay-icon {
            color: white;
            font-size: 3rem;
            opacity: 0.9;
        }

        /* Lightbox Styles */
        .lightbox {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.95);
            display: none;
            align-items: center;
            justify-content: center;
            z-index: 1000;
            backdrop-filter: blur(5px);
        }

        .lightbox.active {
            display: flex;
        }

        .lightbox-content {
            position: relative;
            max-width: 90%;
            max-height: 90%;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .lightbox-image {
            max-width: 100%;
            max-height: 100%;
            object-fit: contain;
            border-radius: 10px;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
            transition: transform 0.3s ease;
        }

        .lightbox-nav {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            background: rgba(255, 255, 255, 0.1);
            border: none;
            color: white;
            font-size: 2rem;
            padding: 15px;
            cursor: pointer;
            border-radius: 50%;
            transition: all 0.3s ease;
            backdrop-filter: blur(10px);
        }

        .lightbox-nav:hover {
            background: rgba(255, 255, 255, 0.2);
            transform: translateY(-50%) scale(1.1);
        }

        .lightbox-prev {
            left: 20px;
        }

        .lightbox-next {
            right: 20px;
        }

        .lightbox-close {
            position: absolute;
            top: 20px;
            right: 20px;
            background: rgba(255, 255, 255, 0.1);
            border: none;
            color: white;
            font-size: 2rem;
            padding: 15px;
            cursor: pointer;
            border-radius: 50%;
            transition: all 0.3s ease;
            backdrop-filter: blur(10px);
        }

        .lightbox-close:hover {
            background: rgba(255, 255, 255, 0.2);
            transform: scale(1.1);
        }

        .lightbox-info {
            position: absolute;
            bottom: 20px;
            left: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.7);
            color: white;
            padding: 20px;
            border-radius: 10px;
            backdrop-filter: blur(10px);
        }

        .zoom-controls {
            position: absolute;
            top: 20px;
            left: 20px;
            display: flex;
            gap: 10px;
        }

        .zoom-btn {
            background: rgba(255, 255, 255, 0.1);
            border: none;
            color: white;
            font-size: 1.5rem;
            padding: 12px;
            cursor: pointer;
            border-radius: 50%;
            transition: all 0.3s ease;
            backdrop-filter: blur(10px);
        }

        .zoom-btn:hover {
            background: rgba(255, 255, 255, 0.2);
            transform: scale(1.1);
        }

        .loading {
            display: inline-block;
            width: 40px;
            height: 40px;
            border: 4px solid #f3f3f3;
            border-top: 4px solid #667eea;
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        @media (max-width: 768px) {
            .gallery-grid {
                grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
                gap: 15px;
            }
            
            .gallery-controls {
                flex-direction: column;
                gap: 10px;
            }
            
            .search-box {
                width: 100%;
                max-width: 300px;
            }
            
            .lightbox-nav {
                font-size: 1.5rem;
                padding: 12px;
            }
        }

Step 3: Adding JavaScript Functionality

This is where the magic happens! We’ll use JavaScript to dynamically load and filter images, handle the lightbox, and add features like zoom.

class ImageGallery {
            constructor() {
                this.images = [
                    {
                        id: 1,
                        src: 'https://picsum.photos/800/600?random=1',
                        thumb: 'https://picsum.photos/400/300?random=1',
                        title: 'Mountain Landscape',
                        description: 'Breathtaking mountain views with misty peaks and serene valleys.',
                        category: 'nature',
                        tags: ['mountains', 'landscape', 'nature']
                    },
                    {
                        id: 2,
                        src: 'https://picsum.photos/800/600?random=2',
                        thumb: 'https://picsum.photos/400/300?random=2',
                        title: 'Modern Architecture',
                        description: 'Contemporary building design with clean lines and geometric patterns.',
                        category: 'architecture',
                        tags: ['building', 'modern', 'design']
                    },
                    {
                        id: 3,
                        src: 'https://picsum.photos/800/600?random=3',
                        thumb: 'https://picsum.photos/400/300?random=3',
                        title: 'Abstract Colors',
                        description: 'Vibrant abstract composition with flowing colors and dynamic forms.',
                        category: 'abstract',
                        tags: ['colors', 'abstract', 'art']
                    },
                    {
                        id: 4,
                        src: 'https://picsum.photos/800/600?random=4',
                        thumb: 'https://picsum.photos/400/300?random=4',
                        title: 'Forest Path',
                        description: 'Peaceful woodland trail surrounded by ancient trees and dappled sunlight.',
                        category: 'nature',
                        tags: ['forest', 'trees', 'path']
                    },
                    {
                        id: 5,
                        src: 'https://picsum.photos/800/600?random=5',
                        thumb: 'https://picsum.photos/400/300?random=5',
                        title: 'City Skyline',
                        description: 'Urban landscape showcasing towering skyscrapers and city lights.',
                        category: 'architecture',
                        tags: ['city', 'skyline', 'urban']
                    },
                    {
                        id: 6,
                        src: 'https://picsum.photos/800/600?random=6',
                        thumb: 'https://picsum.photos/400/300?random=6',
                        title: 'Geometric Patterns',
                        description: 'Intricate geometric design with symmetrical patterns and bold contrasts.',
                        category: 'abstract',
                        tags: ['geometry', 'patterns', 'design']
                    },
                    {
                        id: 7,
                        src: 'https://picsum.photos/800/600?random=7',
                        thumb: 'https://picsum.photos/400/300?random=7',
                        title: 'Ocean Waves',
                        description: 'Powerful ocean waves crashing against rocky shores under dramatic skies.',
                        category: 'nature',
                        tags: ['ocean', 'waves', 'water']
                    },
                    {
                        id: 8,
                        src: 'https://picsum.photos/800/600?random=8',
                        thumb: 'https://picsum.photos/400/300?random=8',
                        title: 'Glass Architecture',
                        description: 'Stunning glass facade reflecting the surrounding environment.',
                        category: 'architecture',
                        tags: ['glass', 'reflection', 'modern']
                    },
                    {
                        id: 9,
                        src: 'https://picsum.photos/800/600?random=9',
                        thumb: 'https://picsum.photos/400/300?random=9',
                        title: 'Fluid Motion',
                        description: 'Dynamic abstract representation of movement and energy in motion.',
                        category: 'abstract',
                        tags: ['motion', 'fluid', 'energy']
                    }
                ];
                
                this.currentIndex = 0;
                this.currentFilter = 'all';
                this.currentView = 'grid';
                this.zoomLevel = 1;
                this.filteredImages = [...this.images];
                
                this.init();
            }

            init() {
                this.renderGallery();
                this.setupEventListeners();
                this.setupKeyboardNavigation();
            }

            renderGallery() {
                const gallery = document.getElementById('gallery');
                gallery.innerHTML = '';

                this.filteredImages.forEach((image, index) => {
                    const item = document.createElement('div');
                    item.className = 'gallery-item';
                    item.dataset.category = image.category;
                    item.dataset.index = index;

                    item.innerHTML = `
                        <img class="gallery-image" src="${image.thumb}" alt="${image.title}" loading="lazy">
                        <div class="gallery-overlay">
                            <div class="overlay-icon">🔍</div>
                        </div>
                        <div class="gallery-info">
                            <h3>${image.title}</h3>
                            <p>${image.description}</p>
                            <div class="gallery-tags">
                                ${image.tags.map(tag => `<span class="gallery-tag">${tag}</span>`).join('')}
                            </div>
                        </div>
                    `;

                    item.addEventListener('click', () => this.openLightbox(index));
                    gallery.appendChild(item);
                });
            }

            setupEventListeners() {
                // Filter buttons
                document.querySelectorAll('.filter-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
                        e.target.classList.add('active');
                        this.filterImages(e.target.dataset.filter);
                    });
                });

                // View buttons
                document.querySelectorAll('.view-btn').forEach(btn => {
                    btn.addEventListener('click', (e) => {
                        document.querySelectorAll('.view-btn').forEach(b => b.classList.remove('active'));
                        e.target.classList.add('active');
                        this.changeView(e.target.dataset.view);
                    });
                });

                // Search box
                document.querySelector('.search-box').addEventListener('input', (e) => {
                    this.searchImages(e.target.value);
                });

                // Lightbox controls
                document.getElementById('closeBtn').addEventListener('click', () => this.closeLightbox());
                document.getElementById('prevBtn').addEventListener('click', () => this.previousImage());
                document.getElementById('nextBtn').addEventListener('click', () => this.nextImage());
                
                // Zoom controls
                document.getElementById('zoomIn').addEventListener('click', () => this.zoomImage(1.2));
                document.getElementById('zoomOut').addEventListener('click', () => this.zoomImage(0.8));
                document.getElementById('zoomReset').addEventListener('click', () => this.resetZoom());

                // Click outside lightbox to close
                document.getElementById('lightbox').addEventListener('click', (e) => {
                    if (e.target.id === 'lightbox') {
                        this.closeLightbox();
                    }
                });
            }

            setupKeyboardNavigation() {
                document.addEventListener('keydown', (e) => {
                    if (document.getElementById('lightbox').classList.contains('active')) {
                        switch(e.key) {
                            case 'Escape':
                                this.closeLightbox();
                                break;
                            case 'ArrowLeft':
                                this.previousImage();
                                break;
                            case 'ArrowRight':
                                this.nextImage();
                                break;
                            case '+':
                            case '=':
                                this.zoomImage(1.2);
                                break;
                            case '-':
                                this.zoomImage(0.8);
                                break;
                            case '0':
                                this.resetZoom();
                                break;
                        }
                    }
                });
            }

            filterImages(category) {
                this.currentFilter = category;
                this.applyFilters();
            }

            searchImages(query) {
                this.searchQuery = query.toLowerCase();
                this.applyFilters();
            }

            applyFilters() {
                let filtered = [...this.images];

                // Apply category filter
                if (this.currentFilter !== 'all') {
                    filtered = filtered.filter(img => img.category === this.currentFilter);
                }

                // Apply search filter
                if (this.searchQuery) {
                    filtered = filtered.filter(img => 
                        img.title.toLowerCase().includes(this.searchQuery) ||
                        img.description.toLowerCase().includes(this.searchQuery) ||
                        img.tags.some(tag => tag.toLowerCase().includes(this.searchQuery))
                    );
                }

                this.filteredImages = filtered;
                this.renderGallery();
            }

            changeView(view) {
                const gallery = document.getElementById('gallery');
                this.currentView = view;
                
                if (view === 'list') {
                    gallery.classList.add('list-view');
                } else {
                    gallery.classList.remove('list-view');
                }
            }

            openLightbox(index) {
                this.currentIndex = index;
                const image = this.filteredImages[index];
                const lightbox = document.getElementById('lightbox');
                const lightboxImage = document.getElementById('lightboxImage');
                const lightboxTitle = document.getElementById('lightboxTitle');
                const lightboxDescription = document.getElementById('lightboxDescription');

                lightboxImage.src = image.src;
                lightboxTitle.textContent = image.title;
                lightboxDescription.textContent = image.description;
                
                lightbox.classList.add('active');
                document.body.style.overflow = 'hidden';
                this.resetZoom();
            }

            closeLightbox() {
                document.getElementById('lightbox').classList.remove('active');
                document.body.style.overflow = 'auto';
            }

            previousImage() {
                this.currentIndex = (this.currentIndex - 1 + this.filteredImages.length) % this.filteredImages.length;
                this.updateLightboxImage();
            }

            nextImage() {
                this.currentIndex = (this.currentIndex + 1) % this.filteredImages.length;
                this.updateLightboxImage();
            }

            updateLightboxImage() {
                const image = this.filteredImages[this.currentIndex];
                const lightboxImage = document.getElementById('lightboxImage');
                const lightboxTitle = document.getElementById('lightboxTitle');
                const lightboxDescription = document.getElementById('lightboxDescription');

                lightboxImage.src = image.src;
                lightboxTitle.textContent = image.title;
                lightboxDescription.textContent = image.description;
                this.resetZoom();
            }

            zoomImage(factor) {
                this.zoomLevel *= factor;
                this.zoomLevel = Math.max(0.5, Math.min(3, this.zoomLevel));
                document.getElementById('lightboxImage').style.transform = `scale(${this.zoomLevel})`;
            }

            resetZoom() {
                this.zoomLevel = 1;
                document.getElementById('lightboxImage').style.transform = 'scale(1)';
            }
        }

        // Initialize gallery when page loads
        document.addEventListener('DOMContentLoaded', () => {
            new ImageGallery();
        });

Step 4: Including Assets (Optional)

This step is optional but recommended for managing external resources like fonts or libraries. Place CDN links to external assets here.

Related posts:

Loading... ...

Loading preview...

Device: Desktop
Dimensions: 1200x800
Lines: 0 Characters: 0 Ln 1, Ch 1

Leave a Comment

About W3Frontend

W3Frontend provides free, open-source web design code and scripts to help developers and designers build faster. Every snippet is reviewed before publishing for quality. Learn more.