💤 Tired: <dialog>
-based HTML+CSS lightboxes
A few years ago I implemented a pure HTML + CSS solution for lightbox images, which I’ve been using on my blog ever since. It works by pre-rendering an invisible <dialog>
for each lightboxable image on the page, linking to the anchor of those dialogs, and exploiting the :target
selector to decide when to make the dialogs visible. No Javascript is required, which means low brittleness and high performance!
<dialog>
-based HTML+CSS lightboxes<dialog>
for each lightboxable image on the page, linking to the anchor of those dialogs, and exploiting the :target
selector to decide when to make the dialogs visible. No Javascript is required, which means low brittleness and high performance! One thing I don’t like about it is that it that it breaks completely if the CSS fails for any reason. Depending upon CSS is safer than depending upon JS (which breaks all the time), but it’s still not great: if CSS is disabled in your browser or just “goes wrong” somehow then you’ll see a hyperlink… that doesn’t seem to go anywhere (it’s an anchor to a hidden element).
A further thing I don’t like about it is it’s semantically unsound. Linking to a dialog with the expectation that the CSS parser will then make that dialog visible isn’t really representative of what the content of the page means. Maybe we can do better.
🚀 Wired: <details>
-based HTML+CSS lightboxes?
Here’s a thought I had, inspired by Patrick Chia’s <details> overlay trick and by the categories menu in Eevee’s blog: what if we used a <details>
HTML element for a lightbox? The thumbnail image would go in the <summary>
and the full image (with loading="lazy"
so it doesn’t download until the details are expanded) beneath, which means it “just works” with or without CSS… and then some CSS enhances it to make it appear like a modal overlay and allow clicking-anywhere to close it again.
Let me show you what I mean. Click on one of the thumbnails below:
Each appears to pop up in a modal overlay, but in reality they’re just unfolding a <details>
panel, and some CSS is making the contents display as if if were an overlay, complete click-to-close, scroll-blocking, and a blur filter over the background content. Without CSS, it functions as a traditional <details>
block. Accessibility is probably improved over my previous approach, too (though if you know better, please tell me!).
The code’s pretty tidy, too. Here’s the HTML:
<details class="details-lightbox" aria-label="larger image"> <summary> <img src="thumb.webp" alt="Alt text for the thumbnail image."> </summary> <div> <img src="full.webp" alt="Larger image: alt text for the full image." loading="lazy"> </div> </details>
The CSS is more-involved, but not excessive (and can probably be optimised a little further):
.details-lightbox { summary { display: block; cursor: zoom-in; &::before { content: ''; backdrop-filter: none; transition: backdrop-filter 0.5s, background 0.2s; background: transparent; } } & > div img { max-width: 95vw; max-height: 95vh; box-shadow: 0 0 12px #fff6; opacity: 0; transition: filter 0.3s, opacity 0.6s; filter: blur(6px); } &[open] > div { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; z-index: 110; pointer-events: none; img { opacity: 1; filter: none; } } &[open] > summary { cursor: auto; &::before { content: ''; background: #000a; backdrop-filter: blur(6px); position: fixed; top: 0; left: 0; width: 100vw; height: 100vw; z-index: 109; } } } body:has(.details-lightbox[open]) { overflow: hidden; }
Native CSS nesting is super nice for this kind of thing. Being able to use :has
on the body
to detect whether there exists an open lightbox and prevent scrolling, if so, is another CSS feature I’m appreciating today.
I’m not going to roll this out anywhere rightaway, but I’ll keep it in my back pocket for the next time I feel a blog redesign coming on. It feels tidier and more-universal than my current approach, and I don’t think it’s an enormous sacrifice to lose the ability to hotlink directly to an open image in a post.
What do you think?
🕵️ Subscribing to DanQ.me's RSS feeds means that you'll get to see secret bonus posts not publicised on the main site. Clever you! 🧠