Confession time. 🙋
My first dark mode implementation was background: black; color: white;.
It looked awful. Users complained. I didn't understand why.
Turns out, dark mode has RULES. And I broke all of them.
🚫 Mistake #1: Using Pure Black
#000000 seems logical for dark mode, right? Maximum darkness!
Wrong.
Did you know? On OLED screens, pure black can cause "smearing" where pixels take longer to turn on, creating ghosting effects when scrolling. It's distracting and looks broken.
Also, pure black with pure white text creates maximum contrast, which sounds good but is actually harder to read for extended periods. It causes eye strain.
The fix: Use dark gray instead. #0B0C15, #1a1a2e, #121212. Close to black, none of the problems.
🚫 Mistake #2: Just Inverting Everything
"Dark mode is just light mode but opposite!"
No. No it is not. 😤
When you invert colors directly:
- Shadows look wrong (shadow below a card should be DARKER, not lighter)
- Images look weird
- Brand colors become unrecognizable
- The whole vibe is off
The fix: Design dark mode as a separate system, not a color inversion filter.
🚫 Mistake #3: Keeping the Same Color Saturation
Your beautiful #3B82F6 blue button? In light mode, it pops.
In dark mode, highly saturated colors on dark backgrounds look aggressive. Almost neon. It's overwhelming.
Did you know? When Apple designed iOS dark mode, they created entirely new color palettes with reduced saturation specifically for dark backgrounds. They didn't just flip a switch.
The fix: Desaturate your colors by 10-20% for dark mode. Same hue, less intensity.
✅ What Good Dark Mode Looks Like
Elevation Through Lightness
In light mode, we show elevation with shadows (card floats above page).
In dark mode, shadows don't work as well. Instead, we show elevation by making higher elements lighter.
/* Light mode: shadow shows depth */
.card-light {
background: white;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
/* Dark mode: lighter bg shows depth */
.card-dark {
background: #1e1e2e;
} /* slightly lighter than page bg */
Use CSS Variables
Please. For the love of all that is holy.
:root {
--bg-primary: #ffffff;
--text-primary: #111111;
}
[data-theme='dark'] {
--bg-primary: #0f0f1a;
--text-primary: #e0e0e0;
}
Toggle the theme, everything updates. No 500 lines of overrides.
Test With Actual Users
Your developer eyes, adjusted to staring at terminals for 12 hours a day, are not representative.
Find someone who uses light mode normally and ask them to try your dark mode. Watch their face. It reveals truth.
📊 Quick Reference
| Element | Light Mode | Dark Mode |
|---|---|---|
| Background | White (#fff) | Dark gray (#0f0f1a) |
| Text | Near black (#111) | Off white (#e0e0e0) |
| Primary color | Full saturation | Reduced 10-20% |
| Elevation | Shadows | Lighter backgrounds |
| Borders | Light gray | Subtle gray |
🎯 The Bottom Line
Dark mode isn't a theme toggle. It's a redesign.
Do it right and users will love you.
Do it wrong and they'll email you at 2AM asking why your app "looks like a hacker terminal from 1985."
Trust me. I've gotten that email. 📧
