Lightbox
A picture opened large over the page, in a native dialog.
On this page
A lightbox is a picture opened large over the page. Use .lightbox on a native <dialog>: the thumbnail's own button opens it with commandfor and command="show-modal", so the browser supplies the top layer, the focus trap and Esc, and no script is involved. The dialog has no sheet of its own. It is exactly as large as the picture, which stands on a page dimmed and blurred well out of focus.
Lightbox
<button class="card card-interactive w(240)" type="button" commandfor="moonstone" command="show-modal"> <img class="card-media" src="/demo/moonstone.svg" alt> <span class="card-header"> <span class="card-title">Moonstone</span> <span class="card-description">View the picture</span> </span></button><dialog class="lightbox" id="moonstone" closedby="any" aria-label="Moonstone" style="--lightbox-ratio: 16 / 9"> <img class="lightbox-media" src="/demo/moonstone.svg" alt="A pale stone over grey hills"> <p class="lightbox-caption">Moonstone, the stone the light theme is named for.</p> <button class="btn btn-sm btn-square lightbox-close" type="button" commandfor="moonstone" command="close" aria-label="Close"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"> <path d="m6 6 12 12M18 6 6 18" /> </svg> </button></dialog>#Opening and closing
commandfor="id"withcommand="show-modal"on the thumbnail's button opens the lightbox.command="close"on the close button closes it and returns focus to the thumbnail.closedby="any"adds light dismiss. Because the dialog is exactly as large as the picture, a click anywhere else is a click outside it, and closes it. A browser that does not know the attribute keeps Esc and the close button.- In a browser without invoker commands, call
dialog.showModal()anddialog.close()from a click handler. The stylesheet is the same.
The picture fades in from a slightly smaller size and leaves faster than it arrived, through @starting-style and discrete transitions; without them it appears and leaves at once.
#Size
lightbox-media goes on an <img>, a <video> or an <iframe>. Its size does not come from the file. It is 64rem wide, or as wide as the viewport's width or height allows with a 24px gutter on every side, at the proportions set in --lightbox-ratio: 3 / 2 unless you say otherwise. So an image, a video and a frame are sized the same way, and nothing moves when one loads.
Set --lightbox-ratio on the dialog to the picture's own proportions, as the example does with 16 / 9; a picture of other proportions is cropped to fit. --lightbox-width sets the widest it gets, and --lightbox-gutter the room kept at the edges.
#Caption and close
lightbox-caption is a floating bar under the picture, as wide as it is; the picture leaves room for it. Keep it to a line or two. lightbox-close goes on a small square button and rests it 8px inside the picture's top corner, where it is found on any picture because it is a raised control with its own edge.
#Lightbox or dialog
A lightbox holds one picture and nothing to decide. An overlay with a title, text or a form is a dialog. A picture that stays in the page with its caption is a figure.
#Accessibility
- Name the dialog with
aria-label, oraria-labelledbypointing at its caption. - Give the large picture a real
alt. The thumbnail inside the button may then have an empty one, when the button's own words say what opens. - Always include a close button with an accessible name: light dismiss and Esc are not found by everyone.
- Focus moves into the lightbox when it opens and returns to the thumbnail when it closes. With reduced motion the picture fades without changing size.
#Classes
| Class | Description |
|---|---|
lightbox | The dialog, with no sheet of its own: it is exactly as large as the picture, over a dimmed and blurred page |
lightbox-media | The picture, a video or a frame: 64rem wide or as large as the viewport allows with a 24px gutter, at the proportions of --lightbox-ratio |
lightbox-caption | A floating bar under the picture, as wide as it is |
lightbox-close | On the close button: it rests 8px inside the top corner of the picture |
#Custom properties
| Property | Default | Description |
|---|---|---|
--lightbox-ratio | 3 / 2 | The picture's proportions, width over height; the picture is cropped to them |
--lightbox-width | 64rem | The widest the picture gets |
--lightbox-gutter | 1.5rem | The room kept between the picture and each edge of the viewport |