Implement and Customize Dark (and light) Mode in CSS

Β· 660 words Β· 4 minute read

Providing support for different dark/light modes on your site goes beyond a mere trend. It has evolved from being an ’extra’ to a functionality that users appreciate and actively use.

According to a study conducted by the Nielsen Norman Group, Dark Mode: How Users Think About It and Issues to Avoid, one-third of users have dark mode configured, one-third have light mode, and the remaining third use a combination of both.

Users identify the following benefits of dark mode:

  • Reduction of eye strain
  • Decreased battery consumption
  • Aesthetic appeal
  • Improved accessibility

The mentioned article addresses these issues, and it’s worth delving into to understand the possible reasons for deciding to invest in creating different modes when building a website.

However, there are two fundamental ideas from the article that I would like to emphasize.

Building in dark mode first is an aesthetic choice; it does not improve usability

For people with visual impairments, it’s best not to enforce either display mode and, instead, respect their system-wide choice.

Implementing and enforcing a dark mode does not benefit usability or accessibility. The primary reason to support different modes should be aesthetic. Under no circumstances should a specific mode be forced. Users should be able to decide which mode they prefer. Enforcing dark mode could negatively impact usability and accessibility for some users.

Now, let’s understand how we can create each of these modes in CSS.

prefers-color-scheme πŸ”—

prefers-color-scheme is a media feature introduced in 2019. Similar to other media features that detect dimensions or support in which the web is being rendered, it allows detecting the preferred mode chosen by the user. Some operating systems allow configuring this mode, and it can also be set in the browser’s own settings.

Like other media features, it uses the @media syntax for detection.

@media (prefers-color-scheme: light) {
  body {
    background: #000;
  }
}

prefers-color-scheme supports values dark and light, enabling the decision of the default implementation and modification based on the user’s preference.

body {
  background: #000;
}

@media (prefers-color-scheme: light) {
  body {
    background: #fff;
  }
}

My recommendation is to use this media feature to set the appropriate CSS variables that can then be utilized throughout the CSS. This way, there’s no need to re-declare each component with its different versions and colors. You only need to configure the values, as if it were a theme.

:root {
  --bg: #000;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #fff;
  }
}

Following this philosophy, we will create variables for each of the different alternatives, each with its color scheme.

:root {
  --bg: #1a1a1a; /* Dark mode background */
  --button-bg: #4d4d4d; /* Dark mode button background */
  --link-underline-color: #999; /* Dark mode link underline color */
  --text-color: #fff; /* Light mode text color */
}

@media (prefers-color-scheme: light) {
  :root {
    --bg: #fff; /* Light mode background */
    --button-bg: #ccc; /* Light mode button background */
    --link-underline-color: #333; /* Light mode link underline color */
    --text-color: #000; /* Dark mode text color */
  }
}

And then in the specific and common implementation:

body {
  background-color: var(--bg);
  color: var(--text-color);
}

button {
  background-color: var(--button-bg);
}

a {
  text-decoration: underline var(--link-underline-color);
}

Declaring the Supported Modes πŸ”—

It is necessary to declare the supported modes so that the browser can choose the one that fits the user’s preference. There are two ways to make this declaration. You only need to do one of them.

Property color-scheme in CSS πŸ”—

The color-scheme property allows various configurations. A common example would be:

:root {
  color-scheme: dark light;
}

There are several combinations you can check in the property documentation, for example, for the night mode.

Meta tag in HTML πŸ”—

The <meta> tags are declared directly in the HTML, allowing the browser to immediately perceive the supported modes without waiting for the CSS to be downloaded. The meta tag used is color-scheme. The way to declare the meta tags is very similar to the CSS property.

<meta name="color-scheme" content="dark light" />
CSS