Key takeaways
- CSS custom properties (variables) like
--brandlet you define colours once and reuse them everywhere. - Dark mode becomes a matter of swapping variable values — not rewriting every rule.
- Respect the visitor’s system preference, offer a manual toggle, and prevent the “flash” of the wrong theme on load.
This website has a light and dark theme that follows your device setting and remembers your choice. Behind it is a simple pattern: design tokens in CSS variables, a data-theme attribute on the <html> element, and a tiny script that runs before the page paints. Here’s how to build the same thing.
CSS custom properties in 60 seconds#
:root {
--brand: #7ed957;
--text: #0f172a;
--bg: #f7f8fb;
--radius: 16px;
}
.button { background: var(--brand); border-radius: var(--radius); }
body { color: var(--text); background: var(--bg); }
Variables cascade and inherit like normal properties, can be changed at any level (.card { --radius: 8px; }) and can be updated with JavaScript at runtime — unlike Sass variables, which disappear at build time.
Design tokens: name by role, not by colour#
| Avoid | Prefer | Why |
|---|---|---|
--white |
--surface |
The surface is dark in dark mode |
--dark-grey |
--text, --muted |
Describes purpose |
--green |
--brand, --on-brand |
Brand can change; text on it needs contrast |
The dark theme#
:root {
--bg: #f7f8fb; --surface: #ffffff; --text: #0f172a; --muted: #5b6477;
--line: rgba(15, 23, 42, .09);
color-scheme: light;
}
[data-theme="dark"] {
--bg: #0b0d12; --surface: #12151d; --text: #e8eaf0; --muted: #98a2b3;
--line: rgba(255, 255, 255, .08);
color-scheme: dark;
}
color-scheme tells the browser to style scrollbars, form controls and default backgrounds to match.
Respect the system preference#
CSS can detect the operating system setting with @media (prefers-color-scheme: dark). To combine it with a manual toggle, resolve the preference in JavaScript and set data-theme:
<script>
(function () {
try {
var saved = localStorage.getItem('theme');
var mode = saved || (matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', mode);
} catch (e) {}
})();
</script>
<head>, before stylesheets. If it runs later (e.g. deferred), dark-mode users see a white flash on every page load.Need a hand with this?
Get a quick, honest review of your website’s SEO.
The toggle button#
<button type="button" id="theme-toggle" aria-label="Switch to dark mode">🌙</button>
<script>
document.getElementById('theme-toggle').addEventListener('click', function () {
var root = document.documentElement;
var next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
root.setAttribute('data-theme', next);
try { localStorage.setItem('theme', next); } catch (e) {}
this.setAttribute('aria-label', next === 'dark' ? 'Switch to light mode' : 'Switch to dark mode');
});
</script>
Dark mode design tips#
- Don’t use pure black backgrounds with pure white text — slightly softer values reduce glare.
- Express elevation with lighter surfaces, not heavier shadows.
- Brand colours may need adjusting: a dark green that works on white can disappear on black. This site uses its logo green as an accent in dark mode and near-black accents in light mode.
- Logos with dark text need a light version (or an SVG using
currentColor). - Check contrast in both themes (4.5:1 for text).
- Update
<meta name="theme-color">so the mobile browser bar matches.
Bonus: color-mix() for derived colours#
--brand-soft: color-mix(in oklab, var(--brand) 12%, var(--surface));
One brand variable can generate soft backgrounds, borders and hover states that automatically adapt to light and dark surfaces.
Dark mode FAQ#
Does dark mode affect SEO?#
No. Search engines render your default styles. Dark mode is a user experience feature.
Should dark mode be the default?#
Follow the visitor’s system preference by default and let them override it.
Can I add dark mode to an existing WordPress theme?#
Yes, if the theme uses CSS variables; otherwise it requires overriding many rules. Some plugins offer automatic dark modes, with mixed results.