← All posts

Theme-aware product screenshots with zero JavaScript frameworks

October 24, 2026 · Dervic

The idea

Every product in the shop now ships with two screenshots: a light one and a dark one. When the visitor toggles the theme, every image on the page swaps instantly - no reload, no flash, no framework.

The markup

Each gallery slide renders both versions and lets CSS decide:

<img class="gallery-light-img" src="product.jpg" alt="">
<img class="gallery-dark-img" src="product-dark.jpg" alt="">

Three lines of CSS

.gallery-dark-img { display: none; }
html[data-theme="dark"] .gallery-light-img { display: none; }
html[data-theme="dark"] .gallery-dark-img { display: block; }

The theme attribute is set once on the element before first paint, so there is never a flash of the wrong image.

Graceful fallback

If the dark screenshot is missing, a tiny onerror handler marks the gallery and the light image simply stays:

<img src="product-dark.jpg" onerror="this.closest('.product-gallery').classList.add('no-dark')">

No dark file? No broken image, no empty box. The whole feature is progressive enhancement - delete both images and the shop still works.

Why not srcset?

srcset picks images by viewport, not by theme. The manual toggle lives in localStorage, so CSS is the only layer that knows about it. Sometimes the boring tools are the right tools.

csstutorial