Sassy dark mode

Backward compatible dark mode

The easiest way to implement dark mode these days is with CSS3 custom properties (variables). Just have a :root element with default colors, and then another one under a media query, and let the user preference do the work. Something like this:

:root {
    --bkg:          white;
    --txt:          black;
}

@media ( prefers-color-scheme: dark ) {
    :root {
        --bkg:      black;
        --txt:      white;
    }
}

body {
    background:     var(--bkg);
    color:          var(--txt);
}

And if the browser doesn’t understand or have the preference, it would take the first set of variables. But if it doesn’t understand variables at all, that’s a problem.

I really hope there is a better solution, because mine feels very silly, but it works. Sass variables. Bare minumum primer: Sass is a preprocessor, it creates a regular CSS file and all the magic happens before that. Also, there’s a pain point if you’re adapting an existing stylesheet: it’s better if the color information has its own section. Lucky for me, I have been doing this since time immemorial.

Ok, to get to the point, we need 6 files. Did I mention it’s silly? style.scss is our main file, which would be our actual style.css at the end. _colors.scss is our color information where we will write it with our variables. Two files for the light and dark variables themselves and two to make a magic trick work.

So, the magic trick is this: we import two files into our main file, and both of those files import a set of variables and our colors file:

_vars_light.scss + _colors.scss → _magic_light.scss

_vars_dark.scss + _colors.scss → _magic_dark.scss

_magic_light.scss + _magic_dark.scss → style.scss

So style.scss would have this:

@import "magic_light";
@media ( prefers-color-scheme: dark ) {
    @import "magic_dark";
}

_magic_light.scss would have this:

@import "vars_light";
@import "colors";

_vars_light.scss would have this:

$bkg:               white;
$txt:               black;

And _colors.scss would have this:

body {
    background:     $bkg;
    color:          $txt;
}

_magic_dark.scss and _vars_dark.scss would “mirror” _magic_light.scss and _vars_light.scss.

BTW, there may be different requirements for how Sass files are handled, I just go by what Hugo does with them and what works for me.

In the end, we have a rather large style.css file with a default light style and a dark style under a media query. Kind of like what we did with CSS3 variables, but that works without them. Silly!


A bit more about Sass.