Let me cook 🔥
"Just add a dark mode toggle. How hard can it be?"
Famous last words. FAMOUS. LAST. WORDS.
Hour 1: Optimism
Easy. CSS custom properties. Light theme. Dark theme. Toggle. Done.
`css
:root {
--bg-primary: #ffffff;
--text-primary: #000000;
}
[data-theme="dark"] {
--bg-primary: #000000;
--text-primary: #ffffff;
}
`
Ship it. We're done here.
Hour 3: The Contrast Problem
Except... inverting colors doesn't work. White text on black background has different perceived contrast than black text on white background.
I need to adjust. Not invert. Adjust.
`css
[data-theme="dark"] {
--bg-primary: #0a0a0a; / Not pure black /
--text-primary: #e0e0e0; / Not pure white /
}
`
Better. But now my brand colors look weird.
Hour 8: The Brand Color Crisis
Our neon green (#00ff88) looks great on dark backgrounds. Looks terrible on light backgrounds. Too bright. Eye-searing.
So I need TWO versions of every brand color.
`css
:root {
--brand-primary: #00cc6a; / Darker for light mode /
}
[data-theme="dark"] {
--brand-primary: #00ff88; / Full neon for dark mode /
}
`
Multiply this by every color in the system.
Hour 16: The Image Problem
Our hero images have dark backgrounds with light text burned in. They look great in dark mode. In light mode, they're jarring.
Do I... make two versions of every image?
No. No, I add a subtle overlay.
`css
.hero-image {
position: relative;
}
[data-theme="light"] .hero-image::after {
content: '';
position: absolute;
inset: 0;
background: rgba(255, 255, 255, 0.1);
mix-blend-mode: overlay;
}
`
Hacky? Yes. Works? Also yes.
Hour 24: The Flash Problem
Page loads in light mode, then JavaScript kicks in and switches to dark mode. Flash of white. Looks broken.
Solution: blocking script in the head.
`html
`
No more flash.
Hour 48: Done?
It works. Light mode. Dark mode. System preference. Manual toggle. Persists across sessions. No flash.
Two days. For a toggle.
Stephen: "Looks great! Can you add a sepia mode too?"
No. No I cannot.
🔥

