Dark Mode CSS: The Complete Implementation Guide
Dark mode is no longer optional. Learn three CSS strategies — system preference detection, class toggle, and cookie persistence — with smooth transitions and zero flash.
U
UIXplor Team
February 25, 2026 · 7 min read
✦
01prefers-color-scheme: The System-First Approach
The `prefers-color-scheme` media query detects the OS setting automatically:
css
:root { --bg: #ffffff; --text: #111111; }
@media (prefers-color-scheme: dark) {
:root { --bg: #0a0a0f; --text: rgba(255,255,255,0.85); }
}
body { background: var(--bg); color: var(--text); }No JavaScript needed. Updates instantly when the user changes their OS preference.
02Class-Based Toggle
For user-controlled toggles, use a class on `<html>`:
css
html.dark { --bg: #0a0a0f; --text: rgba(255,255,255,0.85); }
html.light { --bg: #ffffff; --text: #111111; }
body { background: var(--bg); color: var(--text); transition: background 0.3s ease, color 0.3s ease; }js
const toggle = () => document.documentElement.classList.toggle('dark');03Preventing Flash of Wrong Theme
Add this blocking script in `<head>` (before any CSS) to apply the saved theme before paint:
html
<script>
const saved = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
document.documentElement.classList.add(saved || (prefersDark ? 'dark' : 'light'));
</script>This eliminates the flash by applying the class synchronously during HTML parsing.
04Dark Mode Image Handling
Reduce bright image intensity in dark mode:
css
@media (prefers-color-scheme: dark) {
img:not([src*='.svg']) { filter: brightness(0.85) contrast(1.05); }
}
/* Or use the picture element for different sources */Also invert SVG icons that are dark-on-white:
css
.icon-auto { filter: invert(0); }
@media (prefers-color-scheme: dark) { .icon-auto { filter: invert(1); } }Related UI Components
Related Articles