Dark mode is no longer optional. Most modern operating systems offer it, most users prefer it for at least some contexts, and apps that ship only a light theme look dated. But naive dark mode — inverted colors, harsh contrast, broken elevation — is often worse than no dark mode at all. This guide covers what makes dark mode work.
The Core Decisions
| Element | Light mode | Dark mode |
|---|---|---|
| Surface base | #FFFFFF | #121212 or similar near-black |
| Body text | #111 or #222 | rgba(255,255,255,0.87) |
| Secondary text | rgba(0,0,0,0.6) | rgba(255,255,255,0.6) |
| Elevation | Shadows | Lighter background tints |
| Brand color | Saturated | Desaturate 15-30% |
| Borders | Light gray | Subtle lighter tint |
The Pitfalls
- Pure black backgrounds. Harsh contrast and OLED smearing during scroll. Stick to near-black.
- Pure white text. Vibrates and tires eyes. Use slightly muted white.
- Highly saturated brand colors. Look neon and aggressive on dark. Desaturate.
- Drop shadows for elevation. Mostly invisible on dark surfaces. Use background lightness.
- Same image assets. Photos and screenshots designed for light backgrounds often have white edges or shadow halos that show on dark. Provide dark variants where it matters.
- Inverted colors only. Algorithmic inversion produces ugly, low-contrast palettes. Hand-design dark colors.
The Implementation Pattern
:root {
--bg-surface: #ffffff;
--text-primary: #111111;
--brand: oklch(0.55 0.18 270);
}
:root[data-theme="dark"] {
--bg-surface: #121212;
--text-primary: rgba(255,255,255,0.87);
--brand: oklch(0.7 0.14 270);
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) {
--bg-surface: #121212;
--text-primary: rgba(255,255,255,0.87);
--brand: oklch(0.7 0.14 270);
}
}
Testing Checklist
- Run a contrast audit on the dark palette specifically — light-mode passes don't transfer.
- Check all interactive states (hover, focus, active, disabled) in both modes.
- Test images, illustrations, and screenshots in dark — flag the ones that look wrong.
- Test the theme toggle in both directions, and respect prefers-color-scheme as default.
Try It Yourself
Test colors and palettes for dark mode with DesignKit's color tools.
Color Palette Extractor →