Inverting images for dark mode with pure CSS
A simple CSS trick to make light-background screenshots look good in dark mode without maintaining two versions of every image.
When I added Catppuccin dark mode to this site, most things adapted automatically thanks to DaisyUI’s semantic color classes. But screenshots taken in light mode stuck out: bright white rectangles in an otherwise dark page.
Maintaining dark versions of every image isn’t practical. You can see the result in action on this post about Dependabot. Switch to dark mode and watch the screenshots adapt.
The trick: invert() + hue-rotate()
filter: invert(1) flips all colors. Black becomes white, white becomes black. The problem is that it also inverts all hues: blue becomes orange, green becomes purple.
Adding hue-rotate(180deg) rotates the hues back by 180°, mostly restoring the original colors while keeping the inverted brightness. Not pixel-perfect, but pretty close.
.markdown img:not([src$=".svg"]) {
filter: invert(1) hue-rotate(180deg);
}
SVGs are excluded since they typically use currentColor and already adapt to the theme.
Adding a caption with :has() and ::after
Since the colors won’t be 100% accurate, a small note below each image makes this transparent to readers. Markdown renders images as <p><img /></p>, so :has() can target the wrapping paragraph:
.markdown p:has(> img:not([src$=".svg"]))::after {
content: "(colors inverted for dark mode)";
display: block;
text-align: center;
font-size: 0.75rem;
font-style: italic;
opacity: 0.5;
}
Two filters, one pseudo-element, no build step, zero JavaScript. Works with any dark mode setup and gracefully handles legacy content without touching a single image file.