loading...
Cover image for A cool way to handle scss color variables

A cool way to handle scss color variables

nicolalc profile image Nicola ・2 min read

In my career, I've tried a lot of different ways to handle colours variables in SCSS (or CSS of course).

Every time I try different approaches to handle them, but finally, I've found a cool way to.

The problem

The issue with different theme colours management was the naming convention. Basically I was using something like that:

$background: white;
$primary: magenta;
$secondary: lawngreen;

$light: #FFF;
$dark: #000;

[...]

html {
  background-color: $background;
  color: $dark; /** white on black */
} 

This method has some limitations especially while using different themes palettes. Sometimes switching between dark and light themes doesn't mean than the light colour or the background one might be in contrast with the opposite themes, for example:

/** LIGHT THEME */
$background: black;
$primary: magenta;
$secondary: lawngreen;

$light: #FFF;
$dark: #000;

/** DARK THEME */
$background: white;
$primary: magenta;
$secondary: lawngreen;

$light: #FFF;
$dark: #000;
[...]
html {
  background-color: $background;
  color: $dark; /** black on black with dark theme */
} 

As you can see, you will get unexpected behaviours if you don't set variables and/or CSS properties properly.

The solution

I've tried a lot of different solutions during my career to handle these issues with theming. The best one I've found so far is the following:

/** CONTRAST VARIABLES */
$<variable-name>: black;
$on-<variable-name>: white;

This method allows you to define a colour variable and a contrast colour variable for it.

So if we define two different themes it comes easier to understand and to write:

/** LIGHT THEME */
$background: black;
$on-background: white;
$primary: lawngreen;
$on-primary: black;

/** DARK THEME */
$background: white;
$on-background: black;
$primary: lawngreen;
$on-primary: black;

[...]
html {
  background-color: $background;
  color: $on-background; /** black on white with dark theme */
} 

This system lets you define each variable with its contrast colour, which lets you organize better your themes and styles.

Another cool advantage with this system is the reverse state, for example:

[...]
pre {
  background-color: $primary;
  color: $on-primary;

  &.reversed {
    background-color: $on-primary;
    color: $primary;
  }
} 

Easy! That's all!

Conclusions

This is a cool way to define SCSS (and CSS) variables, I'm using this system in different projects in production and create a new theme is really easy to do.

What do you think about that? Do you know a better method to handle this case? If yes let me know in the comments section!

Discussion

pic
Editor guide
Collapse
capsule profile image
Thibaut Allender

Interesting but this is just highlighting the issue with naming colours after their aspect.
$dark and $light shouldn't be used in the first place.

That being said, if you really want to force using specific backgrounds and colours together, maybe a mixin would be a better approach. Pass the colour name you want for the background, and the mixin will output the correct foreground. That way you really make sure nobody messes things up.

Also I would really recommend namespacing variables. For example, $background should be $color-background. That makes it way easier to find where you used ANY colour variable, and you avoid conflicts by re-using a colour variable by mistake for something else.

Collapse
nicolalc profile image
Nicola Author

That's a nice tip, this example focuses only on naming variables, of course, you might use a mixin to handle them because is the best way to.

I don't use the color- prefix because I use them often by a SCSS map which defines a colour prefix for variables, for example:

$colours: (
  $background: black,
  $on-background: white
);

anyway thanks for the suggestion this might be really useful 🤞

Collapse
capsule profile image
Thibaut Allender

Well I thought about talking about maps too :-)
I rarely use them because it's just too much of a pain to read them back.
$colour-background is way easier to type (and read) than map.get($colours, "background")