This is a picture of me.

Simon Buckley


CSS Variables and System Dark Theme

8 October 2019

If you open this site on a device with a system-wide dark theme enabled, using a browser that supports the feature, you’ll notice the stylesheet adapts to your OS preference.

This is thanks to a new CSS media query that’s seeing widespread adoption in major browsers. At the time of writing, the below browsers and platform combinations support the prefers-color-scheme media query:

Whether your users set ‘dark mode’ for aesthetic purposes, or ergonomic ones, supporting it is simpler than it seems, and your visitors will thank you for it.

To get started adding support for light or dark colour preferences on your website, begin by choosing which you’d like to offer by default, i.e. for users who have not set a preference for this.

In many cases where your content is text-heavy, it’s probably fair to assume that light mode should be the default, as this is what people may already be used to. This will always depend on your audience and your site’s existing design, however.

With that basic task out of the way, let’s get our hands dirty with some code. The basic feature we’ll be making use of in this guide is the browser’s prefers-color-scheme media query. You can check out the cross-browser support at Can I Use

The basic structure of our site will look like this:


In our index.html file, add the below:

<!DOCTYPE html>
    <title>Dark and light!</title>

    <link rel="stylesheet" href="css/styles.css">
    <link rel="stylesheet" href="css/dark.css" media="(prefers-color-scheme:dark)">
    <h1>This is a page title</h1>
    <p>This is some body text</p>
Hey!Did you notice we’re using separate <link> tags for each stylesheet? This is for performance purposes, see here.

Let’s take a look first into our default stylesheet, styles.css:

:root {
    almostWhite: #EEEEEE;
    darkTurquoise: #042A2B
    foreground: var(--darkTurquoise);
    background: var(--almostWhite);
body {
    background-color: var(--background);
    color: var(--foreground);

In this file, I’d like to draw your attention to a couple of things.

  1. We’re using CSS variables. The benefit of this is in the ability to override them in our dark.css file by relying on the CSS cascade.
  2. We’re setting up two sets of variables. One set with colour names, and another with their semantic purpose. This will make your stylesheets easier to maintain in future.

CSS variables have reasonable browser support, however if you need compatibility with any version of Internet Explorer, you’ll need to hardcode the values instead.

Now that our light & default color scheme is sorted, let’s take a look at our dark.css file:

/* DARK.CSS */
:root {
    foreground: var(--almostWhite);
    background: var(--darkTurquoise);

Wait, that’s it?

Because we’re using CSS variables, we don’t need to change any CSS properties on any elements in this simple example. Overriding the variables we’re using will result in an inverted colour experience in this case.

In more complicated site designs, more thought needs to be given than this example above. Below is an example palette based loosely around the design of this site.

Light Theme & No Preference

Background: #EEEEEE

Foreground: #042A2B

Warning: #D84727

Emphasis: #46C7C1

Dark Theme

Foreground: #042A2B

Background: #EEEEEE

Warning: #630000

Emphasis: #46C7C1

Web Development CSS Front-End Design

This post was last updated on 13 November 2019