Ben Fiedler

CSS: prefers-color-scheme

When developing tools that interface with users in a visual sense, I believe it is important to cater to the users' wants (and needs) as much as possible, whilst retaining a recognizable product identity. Probably the brightest decision in this regard is the background color: light or dark?

Specifically regarding webpages, a variety of solutions have been developed: JavaScript triggers, cookie-based theming, user stylesheets and time-based theming. All of these solution falls short in one important aspect: they do not cover 100% of a user’s interaction with a site. The first two solutions have no safe default - they may always show the user the “wrong” theme first, and require active engagement to fix, which is a burden on the user. User stylesheets do work on first visit, however one often has to deal with broken sites, since they were not designed for theming. Finally, time-based theming is silly in its own right1.

The solution

In 2017, the CSS Media Queries Level 5 specification was released, and it proposes the best solution to date: a media query named prefers-color-scheme. It is set by your browser, and can be set to either light or dark - more values may be supported in the future. Instead of requiring a user to interact with each site they visit, the decision is only made once at the browser, and can be applied to every site, even on the first visit! And it is supported by all major desktop and mobile browsers, simply marvelous.

Using this feature is as simple as adding a media query to your styling. Using CSS custom properties (“variables”), all you need to do is define the appropriate colors and you’re good to go.

@media (prefers-color-scheme: light) {
    // light styling
    // the default if no preference set

@media (prefers-color-scheme: dark) {
    // dark styling

The prefers-color-scheme still has one drawback: correct page rendering must be delayed until CSS is downloaded and parsed, and might cause flickering on slow connections, when the browser defaults to a white background but the user prefers dark mode for example. Using the color-scheme meta tag, the webpage can immediately signal which themes it supports, and the browser can react by styling the background dark immediately, before applying CSS, which prevents the aforementioned flickering. The first named theme is the author’s preferred default, which the browser can respect if the user has not given an explicit preference.

<!-- supports light and dark mode, defaults to light mode-->
<meta name="color-scheme" content="light dark">

Trying it out

This website fully supports theme selection based prefers-color-scheme, try it out! It even inverts images2 to perfectly match your preferred style, a feature I’m very proud of, even if it is virtually invisible (since almost nobody looks at both styles). See the website’s source to see the actual SCSS source files.

On desktop browsers you can test it using the developer tools (Firefox, Chrome, Safari). On mobile, modern smartphones (both iOS and Android) set your preferred color scheme based on the system theme, so changing that should also change the appearance of this site.

Sadly, many of the sites I interact with daily do not support prefers-color-scheme. Especially people who rarely do frontend work (such as myself) may not know of this feature, and I hope to raise awareness for user-friendly theme support.

If you have a personal blog, product or company website or any other side, consider adding support for prefers-color-scheme to your theme. Even though it has no impact on the majority of people, we ultimately want design our products to be as user-friendly as possible. Right?

Articles from blogs I follow

Status update, July 2021

Hi! This status update comes a bit late, because I was on leave, biking in the south of France for a few days. This month I’ve released mako 1.6, to try to make up for the long delay for the last release. mako 1.6 brings quality-of-life improvements: modes a…

via emersion on

Paranoid NixOS Setup

Most of the time you can get away with a fairly simple security posture on NixOS. Don't run services as root, separate each service into its own systemd units, don't run packages you don't trust the heritage of and most importantly don't give…

via Christine Dodrill's Blog on

The mythical 10× programmer is just a good leader

There is some truth to the idea that some programmers are more productive than others. In practice, this is mainly a function of the breadth and depth of their experience, rather than an expression of innate talent. Under the right circumstances, the differe…

via Blogs on Sourcehut on