Gather the files and plan the gallery
You need a text editor, a modern browser that supports the HTML dialog element, and a few photos you have permission to use. No package manager, framework, or build tool is required. Create three files named index.html, style.css, and gallery.js, plus an images folder. Open index.html in your browser to try the project.
For each photo, prepare a thumbnail and a larger version. For example, images/garden-small.jpg can represent images/garden-large.jpg. A thumbnail keeps the grid quick to browse, while the larger file is reserved for the full-size view. Use consistent, descriptive filenames so it is easy to pair each image with its larger version. This project works with two photos or twenty; start with three so you can check how the layout behaves.
Create the page structure
In index.html, add the usual document structure, a page heading, a link to style.css, and a script reference to gallery.js with the defer attribute. Inside the main content area, create a container with the class gallery. Give it one button per photo, each with the class thumb and a data-full attribute containing the path to its larger image. Put a thumbnail image inside each button and give that image a short, meaningful alt description. You can add visible caption text inside the button as well. A button makes each photo reachable and activatable with a keyboard without extra JavaScript.
After the gallery, add a dialog with the id viewer. Inside it, place an image with the id full-image and a button with the id close-viewer labeled Close. The dialog will stay closed until JavaScript opens it. Keep the close button easy to find, and avoid putting critical information only in the image: the thumbnail descriptions and any captions should tell visitors what they are choosing. Check that every data-full path points to a file that actually exists.
Make the grid responsive with CSS
Use CSS Grid on .gallery so you do not have to decide the exact number of columns for every device. A useful starting declaration is display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); gap: 1rem;. The columns fit as many items as space allows, and min(100%, 12rem) prevents the minimum width from overflowing a narrow container.
Give .thumb a visible border, a background, and enough padding to make its contents clear. Set the thumbnail images to width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;. Cropping makes varied source images line up neatly, but it can hide important details. If your photos should never be cropped, remove the aspect ratio and use height: auto instead. Add a clearly visible .thumb:focus-visible style so keyboard users can see which photo is selected.
For the larger image, set max-width: min(90vw, 960px); max-height: 80vh; width: auto; height: auto;. Give the dialog comfortable padding and a maximum width that fits the viewport. These limits let the browser scale a large photo down without forcing horizontal scrolling on a small screen; they do not enlarge a small source file into a sharper image.
Open and close the full-size view
In gallery.js, select the dialog, its image, and its close button. Then attach a click listener to every thumbnail button. The following plain JavaScript uses the element names and identifiers described above:
const viewer = document.querySelector('#viewer'); const fullImage = document.querySelector('#full-image'); const closeButton = document.querySelector('#close-viewer'); document.querySelectorAll('.thumb').forEach((button) => { button.addEventListener('click', () => { fullImage.src = button.dataset.full; fullImage.alt = button.querySelector('img').alt; viewer.showModal(); }); }); closeButton.addEventListener('click', () => viewer.close());
The selected button supplies both the larger image path and its description. showModal() opens the dialog above the page content. The Close button calls close(); browsers with dialog support also provide Escape-key closing for a modal dialog. Do not replace the button with an image that only looks clickable: using a real button preserves keyboard access.
Check the result at different sizes
Start with a wide browser window, then narrow it until the gallery becomes a single column. Check for clipped captions, horizontal scrolling, and thumbnails that are difficult to distinguish. Open every photo to confirm its larger file loads and its description matches. Try the gallery using only Tab, Enter or Space, and Escape; the active thumbnail should have a visible focus indicator.
If a photo does not open, check its data-full value against the filename and folder path, including capitalization. If the grid overflows, look for a fixed width on a button or image that conflicts with the responsive rules. These small checks turn a visual demo into a gallery that is more dependable for everyday use.



