Automatic Dark Mode with CSS Variables

Many operating systems offer some form of “dark mode” that allows the user to set their preference for a darker UI, and some can even switch between light and dark themes depending on the time of day. In this post I’ll show you how to use CSS variables to provide light and dark themes for your websites and apps that are applied automatically depending on the user’s preference.

Setting colours with CSS variables

The first step is to make sure the colours you’d like to change between light and dark modes are set using CSS variables. The design for my site is quite simple, so my set of colour variables looks like this:

:root {
  --bg: #f7faff;
  --text: #1e1e1e;
  --codetext: #cd0033;
  --accent: #2175a8;
  --textbg: #e3f4ff;
}

Then in my stylesheet I can use the values like this:

body {
  background: var(--bg);
  border-top: 8px solid var(--accent);
  /* ...other body styles */
}

Alternative variables for dark mode

With variables set for my default light theme, providing a dark theme is as simple as overriding them using the prefers-color-scheme media query, like this:

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1e1e1e;
    --text: #fbfbfb;
    --codetext: #ffb5c7;
    --accent: #3daff3;
    --textbg: #353e42;
  }
}

If a visitor to my site has set their preference for a dark theme either at the OS level or with a browser setting, the value of my --bg CSS variable will be #1e1e1e instead of the default #f7faff specified in the CSS before the media query. In my stylesheet, the CSS styling the background of my pages is still background: var(--bg), it’s just the value of the --bg variable that is different depending on the visitor’s preference.

Here’s how my site currently looks with light and dark themes:

Two screenshots of this website in light and dark modes

What’s more, the transition between the two is automatic with no page refresh needed when the user’s theme changes - perfect if it happens to switch with the time of day while reading!