Dark Mode Color Guide

Why dark mode is not just inverted colors — and how to design dark themes that are genuinely accessible, comfortable, and beautiful.

Why "Invert the Colors" Does Not Work

The naive approach to dark mode is to swap light backgrounds for dark ones and dark text for light. This produces ugly, uncomfortable, and often inaccessible interfaces. The real problems:

Brand colors lose their character

A bright brand blue (#155EEF) on a white background looks vibrant. On a black background, the same blue looks muted and hard to read — it was designed for light mode.

Pure black is too harsh

Pure black (#000000) backgrounds feel oppressive and cause OLED screens to exhibit "smearing" during scrolling. Dark modes typically use dark gray or dark tinted colors instead.

Pure white text is too bright

White (#FFFFFF) text on dark backgrounds creates a halo effect and eye strain, especially on OLED screens. Off-white (#E8EAED or lighter gray) is easier to read.

Shadows do not work

Shadows (dark elements over light backgrounds) disappear on dark backgrounds. Elevation must be communicated differently — usually through lighter surfaces instead of shadows.

The Dark Mode Color Strategy

Base surfaces: dark gray, not black

Use a dark gray, often tinted with the brand hue. Common choices:

  • #121212: Google Material's standard dark surface
  • #0F172A: Slate-900 (Tailwind), blue-tinted dark
  • #1A1A1A: Neutral dark gray
  • #0D1117: GitHub's dark background

Brand-tinted darks feel more cohesive — a brand blue app uses a dark blue-gray background, not a neutral gray.

Elevated surfaces: progressively lighter

Instead of shadows, dark mode uses lighter surfaces to indicate elevation. Standard approach:

  • Level 0 (page background): #121212
  • Level 1 (cards): #1E1E1E (lighter)
  • Level 2 (modals): #2C2C2C (even lighter)
  • Level 3 (popovers): #383838 (lightest)

Each level is roughly 4-8% lighter than the previous.

Text: not pure white

Use off-white for primary text:

  • Primary text: #E8EAED or #E0E0E0 (bright but not harsh)
  • Secondary text: #9AA0A6 or #B0B0B0
  • Disabled text: #5F6368 or #6B6B6B

Contrast against dark backgrounds degrades faster than you expect. Test every text color.

Brand colors: lighter variant

A brand blue that works on white (#155EEF) does not work on dark. Use a lighter tint:

  • Light mode primary: #155EEF
  • Dark mode primary: #4A8CFF or #6BA0FF (lighter, brighter)

The dark-mode variant should be lighter in lightness but similar in hue and saturation.

How OmniColor Uses Dark Mode

OmniColor's dark theme:

  • Background: #0F172A (dark navy, brand-tinted)
  • Surface: #1E293B (one step lighter)
  • Primary: #4A8CFF (lighter than light-mode primary)
  • Text: #F1F5F9 (off-white, not pure white)
  • Border: #2D3A52 (subtle)

Semantic Token Remapping

The cleanest dark mode implementation remaps semantic tokens without touching primitives:

:root {
  --color-background:    #FFFFFF;
  --color-surface:       #F8FAFF;
  --color-text:          #15243B;
  --color-border:        #E3EAF5;
  --color-primary:       #155EEF;
}

[data-theme="dark"] {
  --color-background:    #0F172A;
  --color-surface:       #1E293B;
  --color-text:          #F1F5F9;
  --color-border:        #2D3A52;
  --color-primary:       #4A8CFF;
}

Components reference the semantic tokens and automatically adapt to both themes.

Accessibility in Dark Mode

Contrast is different

Dark mode contrast is not simply the inverse of light mode. A color pair that passes at 4.5:1 in light mode may fail in dark mode because perceived contrast differs.

Always test dark mode colors separately with our contrast checker.

Pure white text on dark is technically high-contrast but exhausting

WCAG might pass, but pure white #FFFFFF on #000000 causes eye strain and halation. Use off-white #E8EAED, which passes AA and feels comfortable.

Images may need adjustments

Dark images on dark backgrounds disappear. Consider adding a subtle border or a light tinted background behind images in dark mode.

Design Considerations

Do not use pure black or pure white

This is the most common dark mode mistake. Use tinted darks and off-whites instead.

Reduce saturation

Bright saturated colors can be overwhelming on dark backgrounds. Slightly desaturate brand colors in dark mode.

Reduce shadows, increase surfaces

Shadows do not work well on dark backgrounds. Use surface elevation instead.

Consider images and media

Photos with white backgrounds look odd in dark mode. Consider providing dark-mode variants or adding padding/borders.

Provide a toggle

Users should be able to choose their preference. Support both prefers-color-scheme system detection AND manual override.

Implementation Options

CSS custom properties

:root { --bg: #FFF; --text: #15243B; }
[data-theme="dark"] { --bg: #0F172A; --text: #F1F5F9; }
body { background: var(--bg); color: var(--text); }

prefers-color-scheme media query

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0F172A;
    --text: #F1F5F9;
  }
}

Combined approach

Use prefers-color-scheme for default detection, plus a user toggle to override. Store the user's choice in localStorage.

Common Mistakes

Pure black background

Feels harsh, causes OLED smearing. Use #0F172A, #121212, or similar tinted darks.

Pure white text

Causes eye strain, halation. Use #E8EAED or off-white.

Same brand colors

Brand colors designed for light mode fail in dark mode. Use lighter, brighter variants.

Relying on shadows

Shadows disappear on dark backgrounds. Use surface elevation instead.

No accessibility testing

Dark mode has its own contrast issues. Test every combination separately.

Not testing on OLED

OLED screens handle dark mode differently than LCD. Test on real devices if possible.

Related Tools

Frequently Asked Questions

Test Dark Mode Contrast →