Press F for key shortcuts
A Shower Of Thoughts

Easier dark-mode CSS with Sass

Published on .

When offering a dark-mode for a website, you probably want to offer an "automatic" or "system" option which follows the OS-level user preference for dark mode instead of explicitly forcing a light or dark mode.
This way, visitors can choose:

  1. dark: for always dark-mode
  2. light: for always light-mode
  3. auto: for automatically switching between dark/light based on operating-system setting.

Writing the CSS for dark-mode that covers these options currently requires a lot of boilerplate, however. With the setup and the Sass mixin I'm sharing next, it should hopefully be easier to handle this.

Note: we're not focusing on the mechanics of how to switch between these options using JavaScript in this post. We're focusing on the CSS implementation specifically.

The setup #

On your document, you're going to add a data-theme attribute to the root <html> whose value will be the currently chosen option:

<!-- always dark-mode -->
<html data-theme="dark"></html>

<!-- automatic / based on system preference -->
<html data-theme="auto"></html>

Again, how you chose to update this value on your pages is outside of the scope of this post.

The Sass Mixin #

Here's the mixin that takes care of everything:

@mixin on-dark-mode {
@media (prefers-color-scheme: dark) {
html[data-theme="auto"] & {
@content;
}
}
html[data-theme="dark"] & {
@content;
}
}

And here's how to use it:

.some-component {
// base / light-mode styles
--bg-color: white;
background-color: var(--bg-color);
color: black;

// dark-mode styles
@include on-dark-mode {
--bg-color: black;
color: white;
}
}

I use this mixin in any Sass project I work on, and so far it has worked nicely!

Limitations: can't be used for root/html styles #

The only downside to this mixin (that I'm aware of) is that it can't be used for declaring dark-mode styles in the :root or html element;
it only works for decendants of it, starting with body.

This means it can't be used to define a set of "global" colors as Custom Properties to be updated based on dark-mode, for instance.

The future: simpler implementation #

Hopefully sometime later in 2023 we will be able to use style queries to simplify and shorten the code needed for robust dark-mode support.

More about: development code-snippet css sass