The StartingUp Summer is also a good time to reopen our archives. After burying the questions AI made obsolete, here's one that survived: this 2021 piece on dark mode in CSS and respecting the theme your visitors chose hasn't aged a bit in substance. From prefers-color-scheme to the light-dark() function that arrived since, we're finally publishing it, warts and all, dusting off only the technical details.
Detecting your visitor's preference with prefers-color-scheme
macOS, Windows, iOS, Android: every system today lets its users choose between a light theme and a dark theme. The browser knows this choice and passes it to your stylesheet through the prefers-color-scheme media query.
This media query is now supported by every browser: you can rely on it with no second thoughts, in pure CSS, without a single line of JavaScript:
Forcing a theme with a toggle button
If you want to let your visitors manually switch themes with a button, you can force these values using CSS variables:
Taking dark mode further with SASS
If you use SASS, I can only encourage you to build yourself mixins to avoid duplicating these somewhat verbose directives all over your code:
Here I choose to add the class indicating the theme on the <html> element rather than on the <body>, so I can also style the <body> element with this mixin.
You'll then be able to easily roll dark mode into all your components inherited this way:
Dark mode: the ultimate level
We can take what we've built even further:
We realize there's no need to duplicate all the code for a light theme, which we could simply define as "the absence of a dark theme."
light-dark(): the shortcut that didn't exist in 2021
CSS has kept moving since these lines were written: the three major engines have supported the light-dark() function since 2024. It lets you declare both variants of a color in a single line, with no media query:
The color-scheme property is essential: it's what tells the browser your page handles both themes. It also gives you an almost free toggle along the way: force color-scheme: light or color-scheme: dark on the <html> element, and all your light-dark() values switch along with it. The function currently only applies to colors; for everything else, the media queries and variables covered above still apply.
Sources:






