All posts

    Designing a Dark Mode Color System That Does Not Just Invert

    Why inverting a light palette produces a bad dark theme, how to build elevation without shadows, and the saturation and contrast adjustments dark surfaces require.

    The fastest way to build a dark theme is to invert every color. The result almost always looks cheap, and the reason is physical: light text on a dark background behaves differently in the eye than dark text on light.

    Never use pure black or pure white

    Pure white text on pure black maxes out at 21:1 contrast, which sounds ideal and reads badly. The extreme ratio causes halation — light characters appear to bleed into the dark background, which is fatiguing over long sessions and noticeably worse for readers with astigmatism.

    Practical anchors:

    • Darkest surface around 8–12% lightness, not 0%
    • Brightest body text around 90–95% lightness, not 100%
    • Target 12:1 to 16:1 for body text rather than the maximum available

    Pure black also breaks elevation, because there is nothing darker to sit behind your lowest surface.

    Elevation comes from lightness, not shadow

    In a light theme, a raised card is signalled with a shadow. Shadows are nearly invisible on dark surfaces — there is not enough range below to cast into.

    Dark themes invert the mechanism: higher elevation means lighter surface. Build a small ladder and use it consistently:

    • Base background — the darkest step
    • Card or panel — one step lighter
    • Popover, dropdown, modal — two steps lighter
    • Tooltip or the topmost layer — three steps lighter

    Steps of roughly 3–4% lightness are enough to read as separation without looking striped. Keep a subtle border on the lightest layers as a backup signal.

    Saturated colors need to be desaturated

    A saturated brand color that looks confident on white looks like it is vibrating on near-black. Two adjustments, applied together:

    Reduce saturation. Highly saturated colors on dark backgrounds appear to glow and cause chromatic aberration at small sizes. Dropping saturation 10–20% for the dark variant usually fixes it.

    Raise lightness. Mid-tone accents that pass contrast on white will fail against dark surfaces. Your dark-theme accent generally needs to be a lighter step of the same hue than your light-theme accent.

    This is why a real dark theme needs its own token values rather than a filter over the light theme. Each semantic token — --primary, --muted-foreground, --border — maps to a different step of the same hue scale per theme.

    Tint the neutrals

    Pure gray surfaces look dead against colored accents. Take your primary hue, drop saturation to 4–8%, and build the neutral ladder from that. On dark backgrounds this cool or warm cast is more noticeable than in light mode, and it is what makes a theme feel designed rather than generated.

    Images and media need attention too

    Transparent PNGs made for light backgrounds often contain dark antialiased edges that turn into visible fringing on dark surfaces. Either ship a second asset or place the logo on a light chip.

    Photographs look harsher. A full-brightness photo against a dark UI is a glare source. Reducing image brightness slightly, or adding a very subtle dark overlay, integrates them better.

    Screenshots of light UI inside a dark article are jarring but usually correct to leave alone — faking a dark-mode screenshot misrepresents the product.

    Verify both themes independently

    Every contrast pair has to be checked twice. A muted gray that passes 4.5:1 on white will not pass on near-black at the mirrored lightness, because the luminance curve is not symmetric. Run the same audit you ran for light mode:

    1. Body text against every surface in the elevation ladder
    2. Muted and secondary text, which is where dark themes usually fail
    3. Borders, input outlines and focus rings at 3:1
    4. Accent color used as text, not just as a fill

    Try it

    • Contrast Checker — test each dark-surface pair against WCAG AA and AAA
    • Palette Generator — generate the monochromatic ladder your elevation steps come from
    • Color Converter — move between HSL for adjusting lightness and HEX for tokens

    Related reading: WCAG Contrast Ratios Explained covers the 3:1 UI-component threshold that dark borders and focus rings so often miss.