Why inverting colours isn’t dark mode
Last updated: 20 August 2026 · By the Eclipse team — this describes the engine we build, so the internals below are first-hand.
The short answer: inversion flips every colour to its opposite. That rotates hues — your favourite site’s blue header comes out orange — and turns photographs into negatives. A real dark theme does something quite different: it works out what each colour is being used for, darkens backgrounds while keeping their hue, recomputes text colours so they stay readable against the new backgrounds, and leaves images completely alone. The one-second test is to load a page with a photo on it.
What inversion actually does
The simplest possible dark mode is one line of CSS: filter: invert(1) over the whole document. Every channel of every pixel becomes its complement. White becomes black, black becomes white — which is the desired result — but so does everything else.
Hue rotation is the visible consequence. Inverting a colour reflects it through the centre of the colour space, and for anything that is not a neutral grey that means it lands on the opposite hue. A blue button becomes orange. A green success message becomes magenta. Every brand on the web loses its identity simultaneously.
Some tools patch this with a second filter, hue-rotate(180deg), which spins hues back toward roughly where they started. It is a real improvement and it is why some filter-based modes look better than others. But it is a global correction applied blindly, so it improves the average case while introducing its own errors, and it does nothing about the deeper problem.
The deeper problem: a filter has no idea what anything is
A filter operates on rendered pixels. At that point in the pipeline, all semantic information is gone. The filter cannot distinguish:
- a page background from a product photograph;
- body text from a logo;
- a border from a drop shadow;
- a decorative gradient from a data visualisation where the colours carry meaning.
That is why photographs come out as negatives. The filter is not making a mistake — it was never given the information required to do anything else.
What a generated theme does instead
The alternative is to work higher up, on the stylesheets and the DOM, where meaning still exists. Broadly:
- Collect the colours the page declares, from its stylesheets and inline styles.
- Assign each a role — surface, text, border, accent, shadow, gradient — based on where and how it is used. This is the step a filter cannot perform.
- Transform each colour according to its role. Surfaces get their lightness compressed toward dark while keeping hue and reducing chroma slightly, since saturated colours read as more intense on dark backgrounds. Borders need different treatment from fills.
- Solve text colours against their actual new backgrounds for a target contrast, rather than assigning a fixed light grey and hoping.
- Map results back into the display’s colour range, since a transformed colour can land outside what the screen can show.
- Leave images alone. A photograph is content, not interface.
Why the colour space matters
Doing step 3 in ordinary RGB produces poor results, because RGB does not correspond to how people perceive colour. Reducing all three channels by the same proportion changes perceived hue and saturation as a side effect, so “just make it darker” drifts colours in ways users notice without being able to name.
Perceptual colour spaces exist to fix this. Eclipse transforms in OKLab, where lightness, chroma and hue are separate, reasonably independent axes. That means lightness can be compressed without dragging hue along with it. A brand blue gets darker and stays recognisably the same blue — which is the entire point, and is not achievable with a filter at all.
Comparing the approaches
| Invert filter | Invert + hue rotate | Generated theme | |
|---|---|---|---|
| Brand colours preserved | No | Approximately | Yes |
| Photographs untouched | No | No | Yes |
| Text contrast controlled | No | No | Yes |
| Per-element control | No | No | Yes |
| Works on any page | Yes | Yes | Mostly |
| Computational cost | Very low | Very low | Higher |
That last row is the honest trade-off, and it is why filter modes still exist in serious extensions. Filters are close to free; generated themes cost real work on every page. How well an extension manages that cost is what separates a fast one from a browser-slowing one.
How to tell which one you are running
- Load a page with a photograph. Darkened or negative photo means a filter.
- Look at a familiar brand colour. If a blue logo is orange, that is raw inversion.
- Find a page that is already dark. A filter will helpfully turn it light.
- Check for a mode setting. Many tools offer both and default to one.
Try it yourself: Eclipse applies a generated dark theme to any site, with per-site overrides and live brightness and contrast controls. Free, no account, no site limits.
Related guides
How Dark Mode Extensions Actually Work
CSS filters, stylesheet rewriting, and generated themes are three different machines. Knowing which one you are running explains every quirk you have hit.
Dark Mode Contrast Done Right: APCA vs WCAG
WCAG’s 4.5:1 ratio was built for dark-on-light and misjudges light-on-dark. Why perceptual contrast models exist and what they change.
Chrome’s Force Dark Mode Flag: What It Does and Where It Breaks
The free option nobody explains properly. How to switch it on, what it does to your images, and the exact page types where it falls apart.
Dark Reader Alternatives: An Honest Comparison
Dark Reader is the category leader and genuinely good. Here is where it struggles — measured, not asserted — and which alternative fits which problem.