I've been building RelahConvert — a browser-only image converter
with 37 tools — and yesterday I decided to add dark mode.
I was expecting it to take hours. It took minutes.
Here's exactly how it works and what I learned.
The Problem With Hardcoded Colors
Most projects start with colors scattered everywhere:
background: #ffffff;
color: #1a1a1a;
border: 1px solid #e0e0e0;
When you have 37 tool pages, finding and replacing every
hardcoded color manually would take forever. There had to be
a better way.
The Solution: CSS Variables + data-theme
The entire dark mode system comes down to two things:
1. Define all colors as CSS variables
:root {
--bg: #ffffff;
--text: #1a1a1a;
--card: #f5f5f5;
--border: #e0e0e0;
}
[data-theme="dark"] {
--bg: #18181b;
--text: #f4f4f5;
--card: #27272a;
--border: #3f3f46;
}
2. Toggle the attribute on the root element
const toggle = () => {
const current =
document.documentElement.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
}
That's the whole system.
Remembering the Preference
You also want to respect the user's OS preference on first
visit, then let them override manually:
// On page load
const saved = localStorage.getItem('theme');
const prefersDark =
window.matchMedia('(prefers-color-scheme: dark)').matches;
const theme = saved || (prefersDark ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
The Toggle Button
A simple sun/moon icon in the navbar:
const icon = theme === 'dark' ? '☀️' : '🌙';
Place it top right — that's where users expect it.
Tips for Dark Mode That Doesn't Look Weird
A few things I learned:
- Never use pure black (#000000) — use #18181b or similar. Pure black feels harsh.
- Never use pure white text — use #f4f4f5. Pure white on dark backgrounds causes eye strain.
- Give cards depth — make cards slightly lighter than the background so elements don't flatten out.
- Watch out for images — if users upload images with white backgrounds, they'll float awkwardly on dark pages. Keep preview areas neutral.
The Result
38 tool pages, all consistently dark, zero hardcoded color
conflicts. The site went from feeling like a utility tool to
feeling like a proper app.
If you're building a Vite SPA and haven't added dark mode yet
— it's simpler than you think. One CSS variable system and a
10-line toggle is all it takes.
Built with Vite. All processing is browser-only — files never
leave the device.
Check it out at relahconvert.com
Top comments (0)