Step 4.2 · Gallery pages
Add the lightbox (JavaScript)
Connect gallery.js so thumbnails open in an accessible lightbox with previous, next and close controls.
JavaScript is the third language of the web:
- HTML defines the content.
- CSS controls how it looks.
- JavaScript controls how it behaves: opening menus, playing slideshows, responding to clicks and keys.
The lightbox uses the browser's built-in <dialog> element. It handles keyboard focus and the Esc key for you, and it needs no plug-ins.
Check that
gallery.jsis in yourjsfolder.Check the link on each gallery page, just before
</body>. The starter gallery page already has it, so your copies do too. Scripts at the bottom run after the gallery HTML has loaded.site/red.html<!-- Lightbox script: keep this just before </body> --> <script src="js/gallery.js"></script> </body>Test it. Click a thumbnail, use the arrows, close it. Then do it all with the keyboard only: Tab to a thumbnail, Enter to open, ← → to move, Esc to close.
Read the script and add your own comment to each numbered part explaining what it does in your words.
The script, explained
// =========================================================
// gallery.js — opens gallery thumbnails in a lightbox
// Uses the browser's built-in <dialog> element. No jQuery needed.
// Link this file at the bottom of each gallery page:
// <script src="js/gallery.js"></script>
// =========================================================
// 1. Find every link inside the gallery list.
const links = Array.from(document.querySelectorAll('.gallery a'));
// Only run the rest if this page has a gallery.
if (links.length > 0) {
// 2. Build the lightbox once and add it to the page.
const lightbox = document.createElement('dialog');
lightbox.className = 'lightbox';
lightbox.setAttribute('aria-label', 'Image viewer');
lightbox.innerHTML = `
<figure>
<img src="" alt="">
<figcaption></figcaption>
</figure>
<button class="lb-prev" type="button" aria-label="Previous image">‹</button>
<button class="lb-next" type="button" aria-label="Next image">›</button>
<button class="lb-close" type="button" aria-label="Close">×</button>
`;
document.body.append(lightbox);
// 3. Keep references to the parts we will change.
const bigImage = lightbox.querySelector('img');
const caption = lightbox.querySelector('figcaption');
let current = 0; // which image is showing (0 = the first one)
// 4. Show image number "index" in the lightbox.
function showImage(index) {
// Wrap around: after the last image, go back to the first.
current = (index + links.length) % links.length;
const link = links[current];
const thumb = link.querySelector('img');
bigImage.src = link.href; // the large image file
bigImage.alt = thumb.alt; // reuse the thumbnail's alt text
caption.textContent =
(link.dataset.caption || thumb.alt) + ' (' + (current + 1) + ' of ' + links.length + ')';
}
// 5. Clicking a thumbnail opens the lightbox instead of a new page.
links.forEach(function (link, index) {
link.addEventListener('click', function (event) {
event.preventDefault();
showImage(index);
lightbox.showModal();
});
});
// 6. Buttons.
lightbox.querySelector('.lb-prev').addEventListener('click', function () {
showImage(current - 1);
});
lightbox.querySelector('.lb-next').addEventListener('click', function () {
showImage(current + 1);
});
lightbox.querySelector('.lb-close').addEventListener('click', function () {
lightbox.close();
});
// 7. Keyboard: arrow keys change images. (Esc closes a dialog automatically.)
lightbox.addEventListener('keydown', function (event) {
if (event.key === 'ArrowLeft') showImage(current - 1);
if (event.key === 'ArrowRight') showImage(current + 1);
});
// 8. Clicking the dark backdrop closes the lightbox.
lightbox.addEventListener('click', function (event) {
if (event.target === lightbox) lightbox.close();
});
// 9. When it closes, put keyboard focus back on the thumbnail.
lightbox.addEventListener('close', function () {
links[current].focus();
});
}| Part | What happens |
|---|---|
| 1 | querySelectorAll('.gallery a') finds every link in the gallery, like a CSS selector. |
| 2 | Creates the <dialog> with an image, caption and three buttons, and adds it to the page. |
| 3 | Stores the parts that change, and current remembers which image is showing. |
| 4 | A function is a reusable set of instructions. showImage swaps in the large image, alt text and caption. The % math wraps from the last image back to the first. |
| 5 | An event listener waits for a click. preventDefault() stops the link opening a new page; showModal() opens the dialog. |
| 6–8 | Buttons, arrow keys and clicking the dark backdrop. |
| 9 | On close, keyboard focus returns to the thumbnail so keyboard users don't lose their place. |
Style the lightbox
The lightbox's look is in section 9 of styles.css. Change the backdrop color, caption font and buttons to match your design.
/* ===== 9. LIGHTBOX (used by js/gallery.js) ===== */
.lightbox {
border: 0;
padding: 0;
background: transparent;
max-width: 92vw;
max-height: 92vh;
overflow: visible;
}
.lightbox::backdrop {
background-color: rgba(0, 0, 0, 0.88);
}
.lightbox img {
max-height: 80vh;
width: auto;
margin: 0 auto;
}
.lightbox figure {
margin: 0;
}
.lightbox figcaption {
color: #ffffff;
text-align: center;
padding: 12px 56px;
}
.lightbox button {
position: fixed;
width: 48px;
height: 48px;
font-size: 2rem;
line-height: 1;
color: #ffffff;
background-color: rgba(0, 0, 0, 0.6);
border: 2px solid #ffffff;
border-radius: 50%;
cursor: pointer;
}
.lightbox button:hover,
.lightbox button:focus-visible {
color: #000000;
background-color: #ffffff;
}
.lb-close { top: 16px; right: 16px; }
.lb-prev { top: 50%; left: 12px; }
.lb-next { top: 50%; right: 12px; }Stretch options
Choose one for bonus credit:
- A thumbnail hover effect using CSS
transition(filters, borders or a caption that slides up) - Swipe left and right on phones (look up
touchstartandtouchendevents) - A fade between images using a CSS
opacitytransition - A mobile menu button that shows and hides the navigation
Look up any part of the script in the W3Schools JavaScript tutorial, for example the dialog element or addEventListener.
© Created by Sara Rosenstock, Marietta College Graphic Design.