Published at
Updated at
Reading time
5min

This post is part of my Today I learned series in which I share all my learnings regarding web development.

User preferences and settings play an essential role in how websites look in 2020. To name two examples: well-made websites look great on different devices and handle various font-size settings with ease.

Over the past few years, a new user preference made it into the group of things "that change how a website looks" – yes, I'm talking about color themes. "How to implement dark mode on a website?" was one of the most important topics in 2019.

(yes... this site will have a dark mode eventually, too)

But how can you enable dark mode then? With today's web technology, your site can react to your visitors' color preferences (coming from the operating system) using the prefers-color-scheme media query. This media query allows you to write CSS depending on the preferred color scheme.

--color-one: #ff0000;
--color-two: #00ff00;

@media (prefers-color-scheme: dark) {
  /* redefine dark mode colors here */
  --color-one: #00ffff;
  --color-two: #ff00ff;
}

Technically, this approach is straight forward, but implementing a high-quality theme handling is not trivial. It includes way more than just switching some colors. To learn more, I recommend reading Thomas Steiner's excellent guide on this topic: "prefers-color-scheme: Hello darkness, my old friend".

# Don't forget to indicate your site's supported color schemes

Having the ability to style websites depending on user color settings is excellent, but unfortunately, it's not covering the whole picture. So what's missing?

Even after writing hundreds of custom CSS lines, there are usually elements still relying on browser default styling. It could be a text input field, a checkbox, a radio button, or even the good old scroll bar using the CSS rules in the browser's user agent stylesheet. The browser doesn't know about your color scheme and comes with default styles based on a light mode. These styles define dark text and highlights on a bright background.

To complete your color scheme and make all your elements dark mode compatible, you have to define and overwrite all these CSS rules from the user agent stylesheet. This process is not ideal!

The color-scheme property helps here. It allows you to give browsers the information on your website's supported color schemes.

color-scheme accepts two values:

  • normal – your site/an element does not support color schemes
  • [ light | dark | <custom-ident> ]+ – your site or a specific element can be rendered with the defined color schemes (custom-ident is currently unsupported and is only defined for possible future use cases)

You can set these values as an HTML meta element or as a CSS declaration.

<!-- Hey Browser, 
     this website support `dark` and `light`
     but the author prefers `dark` representation -->
<meta name="color-scheme" content="dark light">
:root {
  /* Hey Browser, 
     this website support `dark` and `light`
     but the author prefers `dark` representation */
  color-scheme: dark light;
}

With this information, browsers can improve their default styling to match defined color schemes. With adjusted user agent styles, you don't have to overwrite every color to make an element dark mode compatible because the browser took care of it already.

The spec defines the following behavior when a color-scheme property is defined:

If the author has indicated that the page can support this color scheme, the user agent must match the following to the user’s preferred color scheme:

  • the color of the canvas surface
  • the default colors of scrollbars and other interaction UI
  • the default colors of form controls and other "specially-rendered" elements
  • the default colors of other browser-provided UI, such as "spellcheck" underlines

For the example of dark mode, this paragraph means: if a site claims to support a dark color scheme, the browser must provide dark mode compatible colors, form controls, scroll bars and other UI elements.

This browser behavior makes it easier to build color-schemed UIs because default UI elements adjust their color automatically. You can avoid overwriting every color! 🎉

# Browser support of color-scheme

If you go to caniuse.com to check the browser support of color-scheme, you'll be surprised. It looks reasonably good and it seems that only Firefox is missing to support color-scheme.

caniuse.com support table showing that color-scheme is mainly supported only with Firefox missing

Unfortunately, this support table is not telling the whole truth. According to the specification "real support" for color-scheme consists of two things:

  1. the browser must technically support the color-scheme property
  2. the browser must adjust colors and provide UI elements taking color-scheme into consideration

While Chromium browsers technically support color-scheme, they fail on delivering UI elements that are color-scheme: dark-compatible.

Thomas Steiner put together a useful page if you want to have a look. The page toggles the color-scheme property every few seconds going from light to dark and back. This approach allows us to have a look at which elements react to different color schemes.

Chrome UI elements not responding to color-scheme: dark

As you see above, Chrome and Edge 85 are changing the background and text color, but UI elements like inputs and buttons stay the same.

UI elements in Safari that are adjusting to color-scheme: dark

On the other hand, if you look at Safari, you'll see that inputs and buttons change their appearance and seamlessly integrate into a dark color scheme. That's pretty nice!

# Should you use the color-scheme property today?

With Chromium browsers not adjusting their UI elements to a defined color scheme, I don't think that it's prime time for the color-scheme property yet. If you can't rely on elements to "just fit into your dark mode theme" you still have to write all this additional CSS to make UI elements fit in.

Nevertheless, I think that this web platform addition is precious, and maybe we reach complete cross-browser support quickly. 🤞 For my site, I'll add <meta name="color-scheme" content="normal"> to this site until I finally support dark mode. 🙈

# Additional resources

Related Topics

Related Articles