Lightbox
Demo
/* Basic layout styles */
.image-gallery {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.lightbox {
display: none;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(255, 255, 255, 0.9);
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.navigation {
margin-top: 15px;
}
/* Styling for next and previous buttons in lightbox */
.navigation button {
background: rgba(0, 0, 0, 0.5); /* Semi-transparent background */
color: white;
border: none;
padding: 10px 15px;
font-size: 16px;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.3s ease-in-out;
}
.navigation button:hover {
background: rgba(0, 0, 0, 0.7); /* Darker background on hover */
}
/* Styles for animation and interaction */
.thumbnails img:hover {
transform: scale(1.1);
}
/* Style for close button */
.close-btn {
position: absolute;
top: 10px;
right: 10px;
font-size: 24px;
cursor: pointer;
}
/* Enlarged photo */
.enlarged-photo {
text-align: center;
margin-bottom: 20px;
}
/* Additional styles for smaller images */
.thumbnails {
display: flex;
justify-content: space-between;
gap: 5px;
}
.thumbnails img {
width: calc(25% - 3px);
height: auto;
cursor: pointer;
transition: transform 0.3s ease-in-out;
}
/* Styles for thumbnail buttons */
.thumbnail-button {
display: inline-block; /* Ensure they respect their content size */
overflow: hidden; /* Hide overflowing content */
}
.thumbnail-button img {
width: 100%; /* Occupy full width of the button */
height: auto; /* Maintain aspect ratio */
}
/* Adjustments for smaller images on hover */
.thumbnails img:hover {
transform: scale(0.9);
}
/* Hidden state for the lightbox view */
.lightbox-view {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
z-index: 9999;
overflow: auto;
}
.lightbox-view.hidden {
visibility: hidden;
}
/* Centered lightbox content */
.lightbox-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: white;
}
/* Close button in lightbox */
.close-btn {
position: absolute;
top: 10px;
right: 10px;
font-size: 24px;
cursor: pointer;
color: white; /* Change color for better visibility */
background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent background */
padding: 8px 12px;
border-radius: 50%;
z-index: 100; /* Ensures it's above the image */
}
// JavaScript for handling interactions and functionality
const thumbnails = document.querySelectorAll(".thumbnails img");
const thumbnailBtns = document.querySelectorAll(".thumbnail-button");
const enlargedPhoto = document.querySelector(".enlarged-photo");
const lightboxView = document.querySelector(".lightbox-view");
const lightboxImages = document.querySelectorAll(".lightbox-view img");
const lightboxImage = document.querySelector(
".lightbox-view .lightbox-content img"
);
const closeBtn = document.querySelector(".lightbox-view .close-btn");
const nextBtn = document.querySelector(".lightbox-view .next-btn");
const prevBtn = document.querySelector(".lightbox-view .prev-btn");
let currentImageIndex = 0;
let lastFocusedThumbnail = null;
// Function to update the enlarged photo on mouseover or focus
function updateEnlargedPhoto(event) {
if (event.type === "mouseover") {
enlargedPhoto.innerHTML = `
`;
} else if (event.type === "focus") {
enlargedPhoto.innerHTML = `
`;
}
}
// Function to manage focus trap within the lightbox view
function manageFocusTrap(event) {
const focusableElements = [closeBtn, prevBtn, nextBtn];
if (event.shiftKey && event.key === "Tab") {
// If Shift + Tab is pressed, focus the last focusable element
if (document.activeElement === closeBtn) {
event.preventDefault();
nextBtn.focus();
} else if (document.activeElement === prevBtn) {
event.preventDefault();
closeBtn.focus();
}
} else if (event.key === "Tab") {
// If Tab is pressed, focus the first focusable element
if (document.activeElement === nextBtn) {
event.preventDefault();
closeBtn.focus();
} else if (document.activeElement === closeBtn) {
event.preventDefault();
prevBtn.focus();
}
}
}
// Function to open the lightbox view with clicked image
function openLightbox(event) {
let clickedImageSrc;
if (event.target.tagName === "DIV") {
clickedImageSrc = event.target.querySelector("img").src;
} else {
clickedImageSrc = event.target.src;
}
lightboxImages.forEach((image) => {
image.src = clickedImageSrc;
});
lightboxView.classList.remove("hidden"); // Remove the hidden class
lightboxView.style.display = "flex"; // Ensure the lightbox is displayed
document.body.style.overflow = "hidden"; // Prevent scrolling on the main page
lastFocusedThumbnail = event.currentTarget;
// Attach focus trap event listener when the lightbox is opened
document.addEventListener("keydown", manageFocusTrap);
// Delay the focus on the close button after a short timeout
setTimeout(() => {
closeBtn.focus(); // Move focus to the close button
}, 100); // Adjust the delay timing if needed
}
// Functionality to close the lightbox view
function closeLightbox() {
lightboxView.classList.add("hidden"); // Hide the lightbox view
document.body.style.overflow = "auto"; // Restore scrolling on the main page
// Remove focus trap event listener when the lightbox is closed
document.removeEventListener("keydown", manageFocusTrap);
if (lastFocusedThumbnail) {
lastFocusedThumbnail.focus(); // Return focus to the last focused thumbnail
}
}
// Attach event listeners to thumbnails for hover and lightbox opening
thumbnails.forEach((thumbnail) => {
thumbnail.addEventListener("mouseover", updateEnlargedPhoto);
thumbnail.addEventListener("click", openLightbox);
});
thumbnailBtns.forEach((thumbnail) => {
thumbnail.addEventListener("focus", updateEnlargedPhoto);
thumbnail.addEventListener("click", openLightbox);
thumbnail.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
openLightbox(event);
}
});
});
// Functionality to close the lightbox view
closeBtn.addEventListener("click", closeLightbox);
// Function to update the lightbox with the current image
function updateLightboxImage() {
thumbnails.forEach((thumbnail, index) => {
if (index === currentImageIndex) {
lightboxImage.src = thumbnail.src;
}
});
}
// Function to navigate to the next image
function goToNextImage() {
currentImageIndex = (currentImageIndex + 1) % thumbnails.length;
updateLightboxImage();
}
// Function to navigate to the previous image
function goToPrevImage() {
currentImageIndex =
(currentImageIndex - 1 + thumbnails.length) % thumbnails.length;
updateLightboxImage();
}
// Functionality to navigate images using buttons and update lightbox image
nextBtn.addEventListener("click", goToNextImage);
prevBtn.addEventListener("click", goToPrevImage);
// Show the first image initially in the lightbox
updateLightboxImage();
Why use a lightbox component?
A lightbox component serves as a valuable tool in web development by offering a focused and interactive way to display images, videos, or content without navigating away from the main page. It enhances the user experience by presenting visual media in a larger, more prominent view, allowing users to engage with the content while maintaining context within the website. From an accessibility standpoint, a well-implemented lightbox ensures that users with disabilities can navigate through the media content by providing keyboard accessibility, descriptive labels, and compatibility with screen readers. It also prevents the disruption of user flow by overlaying content in a visually appealing manner, making it easier for all users to view and interact with multimedia content without compromising the overall accessibility of the website.
What are some accessibility concerns?
- Keyboard Accessibility
- Concern: Users may have difficulty navigating and interacting with the lightbox using only a keyboard, especially when the focus isn’t appropriately managed.
- Mitigation: Ensure keyboard accessibility by allowing users to open, navigate, and close the lightbox using keyboard controls such as Tab, Enter/Return, and Esc. Manage focus within the lightbox to prevent users from being trapped and ensure a logical tab order.
- Screen Reader Compatibility
- Concern: Screen reader users may struggle to perceive or access content within the lightbox without proper labeling or context.
- Mitigation: Provide appropriate alternative text (alt text) for images and descriptive text for other media types within the lightbox. Ensure the content is announced correctly and the screen reader can access it by managing ARIA attributes and roles.
- Color Contrast and Visibility
- Concern: Insufficient color contrast or poor visibility within the lightbox can impact users with visual impairments.
- Mitigation: Ensure sufficient color contrast between text and background elements within the lightbox. Avoid relying solely on color to convey information, and use other visual cues or text labels to enhance comprehension.
- Focus Management
- Concern: Users might experience focus issues when entering or exiting the lightbox, leading to disorientation or loss of context.
- Mitigation: Manage focus properly by returning focus to the appropriate element when closing the lightbox. Consider using ARIA attributes like aria-modal or aria-hidden to manage focus and ensure proper interaction with assistive technologies.
- Resize and Zoom Compatibility
- Concern: Users might encounter difficulties resizing or zooming in on content within the lightbox, impacting users with low vision.
- Mitigation: Ensure that the lightbox content is responsive and supports resizing without causing loss of information or functionality. Avoid fixed sizes that limit zoom capabilities and provide adequate controls for users to adjust content size if needed.
- Use of Animation or Motion
- Concern: Excessive or distracting animations within the lightbox might be disorienting or cause difficulties for users with motion sensitivities.
- Mitigation: Provide options to disable or limit animations within the lightbox. Ensure that any animations used are subtle, non-distracting, and conform to WCAG guidelines for motion sensitivity.
- All non-text content that is presented to the user has a text alternative that serves the equivalent purpose.
- Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
- If keyboard focus can be moved to a component of the page using a keyboard interface, then focus can be moved away from that component using only a keyboard interface, and, if it requires more than unmodified arrow or tab keys or other standard exit methods, the user is advised of the method for moving focus away.
- If a Web page can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability.
- For all user interface components (including but not limited to: form elements, links and components generated by scripts), the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to user agents, including assistive technologies.