Photo Gallery Project

Create a responsive photo gallery with lightbox and filtering capabilities.

Project Overview

This project will guide you through creating a modern photo gallery using CSS Grid and Flexbox. You'll learn to design responsive image layouts with hover effects and lightbox functionality.

  • Responsive grid layout
  • Image hover effects and overlays
  • Category filtering
  • Lightbox modal for image viewing

Estimated Time

Intermediate: 2-3 hours | Advanced: 1-2 hours

Difficulty Level: Intermediate

Step-by-Step Implementation

1 Create the HTML Structure

HTML Example

<div class="gallery-container">
    <div class="gallery-header">
        <h1>Photo Gallery</h1>
        <div class="gallery-filters">
            <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="city">City</button>
            <button class="filter-btn" data-filter="people">People</button>
        </div>
    </div>
    <div class="gallery-grid">
        <div class="gallery-item" data-category="nature">
            <img src="nature1.jpg" alt="Nature Scene">
            <div class="gallery-overlay">
                <h3>Mountain View</h3>
                <p>Beautiful mountain landscape</p>
                <button class="view-btn"><i class="fas fa-eye"></i></button>
            </div>
        </div>
        <div class="gallery-item" data-category="city">
            <img src="city1.jpg" alt="City Scene">
            <div class="gallery-overlay">
                <h3>City Lights</h3>
                <p>Urban nightscape</p>
                <button class="view-btn"><i class="fas fa-eye"></i></button>
            </div>
        </div>
        <!-- Add more gallery items -->
    </div>
</div>
<!-- Lightbox Modal -->
<div class="lightbox" id="lightbox">
    <div class="lightbox-content">
        <span class="close-btn">×</span>
        <img src="" alt="" id="lightbox-img">
        <div class="lightbox-info">
            <h3 id="lightbox-title"></h3>
            <p id="lightbox-description"></p>
        </div>
    </div>
</div>

2 Add CSS for Layout & Design

Basic CSS Example

.gallery-container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 2rem;
}
.gallery-header {
    text-align: center;
    margin-bottom: 3rem;
}
.gallery-header h1 {
    font-size: 2.5rem;
    margin-bottom: 1.5rem;
    color: #333;
}
.gallery-filters {
    display: flex;
    justify-content: center;
    gap: 1rem;
    flex-wrap: wrap;
}
.filter-btn {
    background: white;
    border: 2px solid #e9ecef;
    padding: 0.75rem 1.5rem;
    border-radius: 25px;
    cursor: pointer;
    transition: all 0.3s;
    font-weight: 500;
}
.filter-btn.active,
.filter-btn:hover {
    background: #667eea;
    color: white;
    border-color: #667eea;
}
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 1.5rem;
    margin-top: 2rem;
}
.gallery-item {
    position: relative;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 4px 15px rgba(0,0,0,0.1);
    transition: transform 0.3s;
}
.gallery-item:hover {
    transform: translateY(-5px);
}
.gallery-item img {
    width: 100%;
    height: 250px;
    object-fit: cover;
    display: block;
}
.gallery-overlay {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: linear-gradient(transparent, rgba(0,0,0,0.8));
    color: white;
    padding: 2rem 1.5rem 1.5rem;
    transform: translateY(100%);
    transition: transform 0.3s;
}
.gallery-item:hover .gallery-overlay {
    transform: translateY(0);
}
.gallery-overlay h3 {
    margin: 0 0 0.5rem 0;
    font-size: 1.2rem;
}
.gallery-overlay p {
    margin: 0 0 1rem 0;
    opacity: 0.9;
}
.view-btn {
    background: rgba(255,255,255,0.2);
    border: none;
    color: white;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    cursor: pointer;
    transition: background 0.3s;
}
.view-btn:hover {
    background: rgba(255,255,255,0.3);
}
/* Lightbox Styles */
.lightbox {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.9);
    z-index: 1000;
}
.lightbox.active {
    display: flex;
    align-items: center;
    justify-content: center;
}
.lightbox-content {
    position: relative;
    max-width: 90%;
    max-height: 90%;
}
.close-btn {
    position: absolute;
    top: -40px;
    right: 0;
    color: white;
    font-size: 2rem;
    cursor: pointer;
    background: none;
    border: none;
}
#lightbox-img {
    max-width: 100%;
    max-height: 70vh;
    border-radius: 8px;
}
.lightbox-info {
    color: white;
    text-align: center;
    margin-top: 1rem;
}
@media (max-width: 768px) {
    .gallery-grid {
        grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
        gap: 1rem;
    }
    .gallery-filters {
        gap: 0.5rem;
    }
    .filter-btn {
        padding: 0.5rem 1rem;
        font-size: 0.9rem;
    }
}

3 Add Interactivity (JS)

Gallery Functionality (JS)

class PhotoGallery {
    constructor() {
        this.currentFilter = 'all';
        this.init();
    }
    
    init() {
        this.bindEvents();
    }
    
    bindEvents() {
        // Filter buttons
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                this.setFilter(e.target.dataset.filter);
            });
        });
        
        // Gallery items
        document.querySelectorAll('.view-btn').forEach(btn => {
            btn.addEventListener('click', (e) => {
                this.openLightbox(e.target.closest('.gallery-item'));
            });
        });
        
        // Close lightbox
        document.querySelector('.close-btn').addEventListener('click', () => {
            this.closeLightbox();
        });
        
        // Close on background click
        document.getElementById('lightbox').addEventListener('click', (e) => {
            if (e.target.id === 'lightbox') {
                this.closeLightbox();
            }
        });
        
        // Keyboard navigation
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') {
                this.closeLightbox();
            }
        });
    }
    
    setFilter(filter) {
        this.currentFilter = filter;
        
        // Update active button
        document.querySelectorAll('.filter-btn').forEach(btn => {
            btn.classList.toggle('active', btn.dataset.filter === filter);
        });
        
        // Filter gallery items
        document.querySelectorAll('.gallery-item').forEach(item => {
            const category = item.dataset.category;
            const shouldShow = filter === 'all' || category === filter;
            
            if (shouldShow) {
                item.style.display = 'block';
                item.style.animation = 'fadeIn 0.5s ease-in';
            } else {
                item.style.display = 'none';
            }
        });
    }
    
    openLightbox(galleryItem) {
        const img = galleryItem.querySelector('img');
        const title = galleryItem.querySelector('h3').textContent;
        const description = galleryItem.querySelector('p').textContent;
        
        document.getElementById('lightbox-img').src = img.src;
        document.getElementById('lightbox-img').alt = img.alt;
        document.getElementById('lightbox-title').textContent = title;
        document.getElementById('lightbox-description').textContent = description;
        
        document.getElementById('lightbox').classList.add('active');
        document.body.style.overflow = 'hidden';
    }
    
    closeLightbox() {
        document.getElementById('lightbox').classList.remove('active');
        document.body.style.overflow = 'auto';
    }
}

// Add CSS animation
const style = document.createElement('style');
style.textContent = `
    @keyframes fadeIn {
        from { opacity: 0; transform: scale(0.9); }
        to { opacity: 1; transform: scale(1); }
    }
`;
document.head.appendChild(style);

new PhotoGallery();

4 Test Responsiveness & Accessibility

Checklist

  • Test on mobile, tablet, and desktop
  • Check keyboard navigation and focus states
  • Use semantic HTML for gallery elements
  • Ensure color contrast is accessible
  • Validate your HTML and CSS

Project Checklist

Back to Chat Interface Next: Form Design