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
- Contrast Checker (test dark mode pairs)
- Design Token Generator (generate dark-mode scales)
- UI Palette Generator
- Color Picker