How to Create a Dark Mode in Sass

A Scalable Method for Color Theming with Developer Experience in Mind

Katie McTigue
Jan 13 · 5 min read

TLDR: Scroll down to “Step 1.”

Why doesn’t Sass have better support for color theming, since it’s all the rage?

Let’s face it, dark modes are trending.

Maybe it’s because the amount of hours per day we spend staring at a screen is only going up.

Maybe it’s because we are using our screen-based devices in low-light environments more and more (in a car at night, in bed, in a hospital command center).

Definitely it’s because Apple did it.

Once upon a time as a part of my job as a UI Designer I was assigned to “make a dark mode” (more on that and why it maybe wasn’t the best way to approach here.) I eagerly googled “how to color theme sass,” fully expecting to be able to do something along the lines of this:

//how NOT to do color theming in Sass, unfortunately$background;if ($theme == 'dark') {
$background: #333;
} else {
$background: #ebebeb;
}
.my-div {
background: $background;
}

I don’t know if this speaks to my inability to understand Sass, or to Sass’s inability to anticipate developer needs, but the fact is Sass compiles to good ole css — it’s a preprocessor and not a full-fledged language. Therefore it can’t just swap all your variables on the fly after it is already compiled.


The current prominent approach to theming in Sass

Fortunately there are some excellent ideas on the web for how to solve this problem. They all boil down to more or less the same thing:

  1. Assign a toggle-able “root” theme class to the body element (or app root, for React land) like theme--light.

It will compile to something like this:

.theme--dark {
.my-div {
background: #333;
}
}
.theme--light {
.my-div {
background: #ebebeb;
}
}

Isn’t there a better way to do this?

It was hard for me to come to terms with the fact that you can’t just switch out the value of variables on the fly. It was hard on my architect, too. We were pretty sure there had to be a better way.

Well. In my research and brainstorming, I found three viable approaches to theming a web app with (or without) Sass:

  1. Write a whole new stylesheet for your dark mode. Oof. This is quite ugly because it makes for a lot of code, and your engineers will have to update two stylesheets every time something changes!
My notes from debating methods for color theming when I was assigned to create a dark mode for a very complex interactive dashboard (built with some very old legacy code, and no Sass)

My version of the current prominent Sass method

Goals:

  1. Developer friendly. Love ‘em to death, but most of the engineers I currently work with absolutely hate writing css.

Ok, here goes. If you’re scrolling through this waiting for the part where I tell you how to do the thing, stop here.

My method is largely based on an excellent article written by Dmitry Borody but tweaked to meet my above goals.

I implemented theming on my personal website. You can view the source code here.

Step 1. Make your themes. Fun!

I have everything in a Sass partial called _color-themes.scss.

You can define pretty much whatever you want here. Note that I have a different version of my logo for each theme, and also that I am passing in a gradient for my background on my dark theme, but not the light theme.

I am passing in Sass variables, but you could use hex values.

Step 2. A fancy mixin

Here’s what’s happening here:

  • The themed mixin iterates through all of your $themes and for that theme defines a global Sass map called $theme-map

It outputs the themed blurb using @content

Step 3. The “more on that in a sec” part: how to call the theming function and mixin from within your stylesheets

Each time you want to use a theme, call the themed mixin with @include themed() and inside it use the t() function around your key.

I was worried about having developers write strings ever time they wanted to use a variable, so I added shortcuts at the top of my _color-themes.scss file that simply output strings that match the keys in my $themes object.

$bg: 'bg';
$card-bg: 'card-bg';
$text: 'text';
$text-secondary: 'text-secondary';
$link: 'link';
$hover: 'hover';
$logo: 'logo';
$brand-blue: 'brand-blue';
$brand-red: 'brand-red';
$border: 'border';

These are what I’m passing into @t like color: t($text); but I could also do color: t(‘text’);.

Step 4. Toggle the theme!

Here is how I did it on my website which I built in React.

Your outputted css should follow this format!

.theme--dark {
.my-div {
background: #333;
}
}
.theme--light {
.my-div {
background: #ebebeb;
}
}

See my example here

As mentioned earlier, I implemented theming on my personal website. You can view the source code here. If you have any feedback or ideas for improvement I’d love to hear them!

Additional mixins

If and when I implement this in an enterprise environment, I plan to leverage @extend to create reusable blocks of the most common color combinations in the hopes that this will help minimize margin of error:

%card-colors {
@include themed() {
color: t($text);
background: t($card-bg);
border: t($card-bg);
}
}

This is still not that great.

At the end of the day, there are some problems with this method:

  • Room for error

Dear Sass,

Please build support for theming into your framework!

❤ , me

Katie McTigue

Written by

Designer & Developer. katiemctigue.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade