Dark mode with CSS custom properties and color-scheme
Switch themes by redefining variables under prefers-color-scheme, with a manual override attribute.
- CSS
- GreenSnippets
- MIT
:root {
color-scheme: light dark;
--bg: #fafaf7;
--fg: #16181a;
--accent: #15803d;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg: #0b0d0c;
--fg: #ecefed;
--accent: #2ee55a;
}
}
:root[data-theme="dark"] {
color-scheme: dark;
--bg: #0b0d0c;
--fg: #ecefed;
--accent: #2ee55a;
}
body {
background: var(--bg);
color: var(--fg);
}How it works
Define colors once as custom properties and override them for dark mode. color-scheme tells the browser to render built-in controls and scrollbars in the matching theme. The [data-theme] selectors let a toggle override the OS preference; the :not([data-theme="light"]) guard keeps an explicit light choice from being overridden by a dark OS.
Check contrast in both themes (WCAG AA is 4.5:1 for body text).
This snippet has been reviewed but was not executed by an automated test. Test it in your own environment before relying on it.
Related snippets
- CSS
Respect prefers-reduced-motion
Turn off or shorten animations for users who ask their system for less motion.
- CSS
Accessible focus ring with :focus-visible
Show a clear focus outline for keyboard users without drawing it on mouse clicks.
- HTML
Accessible modal with the dialog element
Use the native dialog element for a modal with built-in focus trapping, Escape to close and a backdrop.
- HTML
Accordion with details and summary
A keyboard-accessible FAQ accordion with no JavaScript, including an exclusive group using the name attribute.

