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

Install NetBSD 9.2 on a DEC Alpha CPU with AXPBox

This is a guide on installing and running NetBSD 9.2 for the DEC Alpha CPU architecture on AXPbox, the open source Alpha Emulator. I recently wrote an article on how to install NetBSD in QEMU for Alpha and since I'm involved with the AXPbox project th…

via Raymii.org on

Introducing a GraphQL-native approach to webhooks

Today, we are shipping a new system for webhooks for use with our suite of GraphQL APIs, which are under development as part of our larger beta plans. We’re not the first to use this design for webhooks, but it is somewhat uncommon, so I’ll take this opportu…

via Blogs on Sourcehut on

Programmers Don’t Understand Hash Functions

Programmers don’t understand hash functions, and I can demonstrate this to most of the people that will read this with a single observation: When you saw the words “hash function” in the title, you might have assumed this was going to be a blog post about…

via Cryptography – Dhole Moments on