Dark mode
Many people turn on a dark theme in their system: the eyes get less tired in the evening, and a phone saves battery. A site can follow this choice. The basis of a dark theme is keeping colors in variables and changing their values in one place.
The prefers-color-scheme media query
The prefers-color-scheme media query tells which theme the user chose in the system: light or dark:
<style>
.box { padding: 16px; background: white; color: black; border: 1px solid silver; }
@media (prefers-color-scheme: dark) {
.box { background: #1e1e24; color: #eee; }
}
</style>
<div class="box">The block color depends on the system theme</div>The example follows the theme of your operating system, not the switch on this site. To see the dark version, turn on the dark theme in your system or emulate it in the developer tools (in Chrome — the Rendering panel, the "Emulate CSS prefers-color-scheme" option).
Colors in variables
If colors are scattered across all rules, a dark theme means rewriting each of them. It is easier to declare variables — custom properties — and change only them in the media query:
<style>
.page {
--bg: white;
--text: #222;
--accent: steelblue;
padding: 16px;
background: var(--bg);
color: var(--text);
}
.page a { color: var(--accent); }
@media (prefers-color-scheme: dark) {
.page { --bg: #1e1e24; --text: #eee; --accent: lightskyblue; }
}
</style>
<div class="page">The text and the <a href="#">link</a> take their colors from variables.</div>Variables are usually set on :root — the root of the whole page.
The color-scheme property
The browser draws scrollbars, input fields and buttons by itself. The color-scheme property tells it which themes the page supports, and the built-in elements get dark too:
:root {
color-scheme: light dark;
}With this line, in a dark system the default page background becomes dark, the text light, and form fields dark.
The light-dark() function
The light-dark() function takes two colors: for the light and for the dark theme. It works only when color-scheme is set, and saves you a separate media query:
:root {
color-scheme: light dark;
--bg: light-dark(white, #1e1e24);
--text: light-dark(#222, #eee);
}The function arrived in all major browsers in 2024.
A switch on the site
Often the theme can be chosen right on the site. Then the dark colors are turned on by a class or, as here, by the state of a checkbox through :has(). Tick the checkbox:
<style>
.site { --bg: white; --text: #222; padding: 16px; background: var(--bg); color: var(--text); transition: background 0.3s; }
.site:has(#dark:checked) { --bg: #1e1e24; --text: #eee; }
</style>
<div class="site">
<label><input type="checkbox" id="dark"> Dark theme</label>
<p>Anna is reading an article in the evening.</p>
</div>Real sites remember the choice with JavaScript and put a dark class on the <html> element.
Common mistake
A color set bypassing the variables does not change in the dark theme. The result is dark text on a dark background:
<style>
.site { --bg: #1e1e24; --text: #eee; padding: 16px; background: var(--bg); color: var(--text); }
.price { color: #333; }
</style>
<div class="site">
<p>Normal text is visible.</p>
<p class="price">Price: $20, barely visible</p>
</div>Take all the colors of a component from variables, and after turning on the dark theme go through the pages and check each one.