Created
June 25, 2025 09:02
-
-
Save lam0819/134a59863442cc9cbabb3a9785253ae5 to your computer and use it in GitHub Desktop.
Simple ImageLightbox
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ImageLightbox { | |
constructor(options = {}) { | |
// Configuration | |
this.config = { | |
autoMode: false, // Set to true for automatic mode, false for explicit only | |
selectors: [ | |
'img.lightbox-trigger', | |
'img[data-lightbox]', | |
'img.lightbox-enabled' | |
], | |
...options | |
}; | |
this.images = []; | |
this.currentIndex = 0; | |
this.lightbox = null; | |
this.lightboxImg = null; | |
this.init(); | |
} | |
init() { | |
this.createLightboxHTML(); | |
this.addStyles(); | |
this.attachEvents(); | |
this.scanImages(); | |
} | |
createLightboxHTML() { | |
this.lightbox = document.createElement('div'); | |
this.lightbox.id = 'js-lightbox'; | |
this.lightbox.innerHTML = ` | |
<div class="lightbox-content"> | |
<button class="close-btn" id="lightbox-close">×</button> | |
<button class="nav-btn prev-btn" id="lightbox-prev">‹</button> | |
<button class="nav-btn next-btn" id="lightbox-next">›</button> | |
<img id="lightbox-img" src="" alt=""> | |
<div class="image-counter" id="lightbox-counter"></div> | |
</div> | |
`; | |
document.body.appendChild(this.lightbox); | |
this.lightboxImg = document.getElementById('lightbox-img'); | |
} | |
addStyles() { | |
const style = document.createElement('style'); | |
style.textContent = ` | |
#js-lightbox { | |
display: none; | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background-color: rgba(0, 0, 0, 0.9); | |
z-index: 10000; | |
opacity: 0; | |
transition: opacity 0.3s ease; | |
justify-content: center; | |
align-items: center; | |
} | |
#js-lightbox.active { | |
display: flex; | |
opacity: 1; | |
} | |
#js-lightbox .lightbox-content { | |
position: relative; | |
max-width: 90%; | |
max-height: 90%; | |
transform: scale(0.8); | |
transition: transform 0.3s ease; | |
} | |
#js-lightbox.active .lightbox-content { | |
transform: scale(1); | |
} | |
#js-lightbox img { | |
width: 100%; | |
height: auto; | |
max-width: 100%; | |
max-height: 90vh; | |
object-fit: contain; | |
border-radius: 8px; | |
} | |
#js-lightbox .close-btn { | |
position: absolute; | |
top: -40px; | |
right: 0; | |
background: none; | |
border: none; | |
color: white; | |
font-size: 30px; | |
cursor: pointer; | |
width: 40px; | |
height: 40px; | |
border-radius: 50%; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
transition: background-color 0.3s ease; | |
} | |
#js-lightbox .close-btn:hover { | |
background-color: rgba(255, 255, 255, 0.2); | |
} | |
#js-lightbox .nav-btn { | |
position: absolute; | |
top: 50%; | |
transform: translateY(-50%); | |
background: rgba(255, 255, 255, 0.2); | |
border: none; | |
color: white; | |
font-size: 24px; | |
cursor: pointer; | |
width: 50px; | |
height: 50px; | |
border-radius: 50%; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
transition: background-color 0.3s ease; | |
} | |
#js-lightbox .nav-btn:hover { | |
background-color: rgba(255, 255, 255, 0.4); | |
} | |
#js-lightbox .prev-btn { | |
left: -70px; | |
} | |
#js-lightbox .next-btn { | |
right: -70px; | |
} | |
#js-lightbox .image-counter { | |
position: absolute; | |
bottom: -40px; | |
left: 50%; | |
transform: translateX(-50%); | |
color: white; | |
font-size: 14px; | |
background: rgba(0,0,0,0.5); | |
padding: 5px 10px; | |
border-radius: 15px; | |
} | |
@media (max-width: 768px) { | |
#js-lightbox .nav-btn { | |
width: 40px; | |
height: 40px; | |
font-size: 20px; | |
} | |
#js-lightbox .prev-btn { | |
left: 10px; | |
top: 20px; | |
transform: none; | |
} | |
#js-lightbox .next-btn { | |
right: 10px; | |
top: 20px; | |
transform: none; | |
} | |
#js-lightbox .close-btn { | |
top: 10px; | |
right: 50%; | |
transform: translateX(50%); | |
} | |
} | |
img.lightbox-enabled { | |
cursor: pointer; | |
transition: transform 0.3s ease, box-shadow 0.3s ease; | |
} | |
img.lightbox-enabled:hover { | |
transform: scale(1.05); | |
box-shadow: 0 8px 25px rgba(0,0,0,0.3); | |
} | |
`; | |
document.head.appendChild(style); | |
} | |
scanImages() { | |
if (this.config.autoMode) { | |
// AUTOMATIC MODE: All images get lightbox | |
const allImages = document.querySelectorAll('img'); | |
this.images = Array.from(allImages); | |
} else { | |
// EXPLICIT MODE: Only images with specific classes/attributes | |
const selector = this.config.selectors.join(', '); | |
const explicitImages = document.querySelectorAll(selector); | |
this.images = Array.from(explicitImages); | |
} | |
// Add click events and styling to selected images | |
this.images.forEach((img, index) => { | |
img.classList.add('lightbox-enabled'); | |
img.addEventListener('click', (e) => { | |
e.preventDefault(); | |
this.openLightbox(index); | |
}); | |
}); | |
} | |
attachEvents() { | |
document.getElementById('lightbox-close').addEventListener('click', () => this.closeLightbox()); | |
this.lightbox.addEventListener('click', (e) => { | |
if (e.target === this.lightbox) { | |
this.closeLightbox(); | |
} | |
}); | |
document.getElementById('lightbox-prev').addEventListener('click', () => this.prevImage()); | |
document.getElementById('lightbox-next').addEventListener('click', () => this.nextImage()); | |
document.addEventListener('keydown', (e) => { | |
if (!this.lightbox.classList.contains('active')) return; | |
switch(e.key) { | |
case 'Escape': | |
this.closeLightbox(); | |
break; | |
case 'ArrowLeft': | |
this.prevImage(); | |
break; | |
case 'ArrowRight': | |
this.nextImage(); | |
break; | |
} | |
}); | |
} | |
openLightbox(index) { | |
this.currentIndex = index; | |
this.updateImage(); | |
this.lightbox.style.display = 'flex'; | |
setTimeout(() => { | |
this.lightbox.classList.add('active'); | |
}, 10); | |
document.body.style.overflow = 'hidden'; | |
} | |
closeLightbox() { | |
this.lightbox.classList.remove('active'); | |
setTimeout(() => { | |
this.lightbox.style.display = 'none'; | |
document.body.style.overflow = ''; | |
}, 300); | |
} | |
updateImage() { | |
const currentImg = this.images[this.currentIndex]; | |
this.lightboxImg.src = currentImg.src; | |
this.lightboxImg.alt = currentImg.alt || ''; | |
document.getElementById('lightbox-counter').textContent = `${this.currentIndex + 1} / ${this.images.length}`; | |
const prevBtn = document.getElementById('lightbox-prev'); | |
const nextBtn = document.getElementById('lightbox-next'); | |
if (this.images.length > 1) { | |
prevBtn.style.display = 'flex'; | |
nextBtn.style.display = 'flex'; | |
} else { | |
prevBtn.style.display = 'none'; | |
nextBtn.style.display = 'none'; | |
} | |
} | |
prevImage() { | |
this.currentIndex = this.currentIndex > 0 ? this.currentIndex - 1 : this.images.length - 1; | |
this.updateImage(); | |
} | |
nextImage() { | |
this.currentIndex = this.currentIndex < this.images.length - 1 ? this.currentIndex + 1 : 0; | |
this.updateImage(); | |
} | |
addImage(imgElement) { | |
if (!this.images.includes(imgElement)) { | |
this.images.push(imgElement); | |
imgElement.classList.add('lightbox-enabled'); | |
imgElement.addEventListener('click', (e) => { | |
e.preventDefault(); | |
this.openLightbox(this.images.indexOf(imgElement)); | |
}); | |
} | |
} | |
refresh() { | |
this.images = []; | |
this.scanImages(); | |
} | |
// Public method to toggle auto mode | |
setAutoMode(enabled) { | |
this.config.autoMode = enabled; | |
this.refresh(); | |
} | |
} | |
// Initialize with configuration | |
if (document.readyState === 'loading') { | |
document.addEventListener('DOMContentLoaded', () => { | |
// CONFIGURATION - Change autoMode here | |
window.imageLightbox = new ImageLightbox({ | |
autoMode: false // Set to true for automatic, false for explicit only | |
}); | |
}); | |
} else { | |
window.imageLightbox = new ImageLightbox({ | |
autoMode: false // Set to true for automatic, false for explicit only | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- These will have lightbox --> | |
<img src="image1.jpg" class="lightbox-trigger" alt="Image 1"> | |
<img src="image2.jpg" data-lightbox alt="Image 2"> | |
<img src="image3.jpg" class="lightbox-enabled" alt="Image 3"> | |
<!-- These will NOT have lightbox --> | |
<img src="logo.jpg" alt="Logo"> | |
<img src="icon.png" alt="Icon"> | |
<script> | |
// Explicit mode (default) | |
window.imageLightbox = new ImageLightbox({ autoMode: false }); | |
// Automatic mode | |
window.imageLightbox = new ImageLightbox({ autoMode: true }); | |
// Switch to automatic mode | |
window.imageLightbox.setAutoMode(true); | |
// Switch to explicit mode | |
window.imageLightbox.setAutoMode(false); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment