CSS & SASS hybrid variables

Using an hybrid approach to get the best of both.
Posted in CSS, the 15/10/2020.

A short comparison

I’ve been a Sass user for many years, well over before CSS variables exist. I’ve always appreciated its variables and mixins mechanisms. As a developer it speaks to me and I can take advantage of those to make my styles more adaptable to changes.

The tradeoff though is that Sass must go through a compilation phase to interpret those variables and overall Sass code, which is then outputed as a plain CSS file.

If we take for example a context where you want to have a light or dark mode on your website, which seems pretty popular these days. You may have some very clever and concise Sass code to generate those variants in your Sass files. After compilation, it may output far more lines in the computed CSS file.

In the meantime, variables where then introduced in CSS. One could argue that there would not be much added value in having another system of variables if you already used Sass ones, but I see two benefits :

  • They can be complementary. The fact that you use a system of variables does not rule you of using the other if it benefits you in certain (even small) cases.
  • CSS variables do not have to be compiled to work in your browser. Which for me is actually the biggest advantage. One that overcomes the shortcomings of Sass variables.
    • You can change their values on the fly directly from your browser devtools and see the global impact of those changes live on your page. It’s not that easy to do with Sass variables because the computed CSS you get after compilation is a plain text value, and not a variable anymore.
    • The computed CSS is more concise when implementing variants (light / dark mode for example), because you can change the variable definition from within a context. I insist on variable definition vs property override. In CSS to implement a variant you can change the variable definition, and all the properties based on this variable will adapt right away. Whereas in Sass you must override the colored properties to specify the use of another Sass variable instead, which is lengthier.

To sum up, to me Sass variables are more effective in the dev stage. It’s powerful, very programmatic, I’m used to it, it’s well integrated into IDEs which adds many advantages (code completion, jump to definition, linting, color preview…). On the other hand CSS variables really shine in the browser. It’s dynamic, adaptable, and can make you write less code to generate variants.

That’s why on this website I wanted to experiment using both, to see if I could benefit from both sides.

Using both : the hybrid approach

The approach can be explained like this : I’ll use SASS variables in my code, but the sass variable value, is in fact a CSS variable. That way I can benefit from both sides : the robustness, rigor and IDE integration of sass variables, and the dynamic aspect of CSS variables, allowing me to test changes from my web inspector for example.

Here’s how it works in practice. Please note that there are two distinctive parts : one about color definition, one about variables definition. The first part can be omitted.

1.1 : First, I declare my colors as Sass variables:

//Sass variables definition
$lightColor:#f7f7f7;
$darkColor:#3A3A3A;
$darkerColor:#1A1A1A;

1.2 : Then I declare CSS variables with the help of my Sass variables that holds the color value:

//CSS variables definition
:root {
  --dark: $darkColor;
  --darker: $darkerColor;
  --light: $lightColor;
  --links: $linksColor;
  --linksHover: $linksHoverColor;
}

2.1 : Next step, where it gets a little trickier, I declare a Sass variable to represent not the color anymore, but the CSS color variable.

//CSS variables declared as SASS variables
$darkVar: var(--dark);
$darkerVar: var(--darker);
$lightVar: var(--light);
$linksVar: var(--links);
$linksVarHover: var(--linksHover);

2.2 : Now when I need a color in my code, I use the Sass variable that represents the CSS variable declaration:

//Using Sass variable that represents the CSS variable declaration.
body {
  color: $darkVar;
  background: $lightVar;
}

And here’s the output you get after compilation :

//Output
:root {
    --dark: #3A3A3A;
    --darker: #1A1A1A;
    --light: #f7f7f7;
    --links: #3A3A3A;
    --linksHover: #3A3A3A;
}
body {
    color: var(--dark);
    background: var(--light);
}

Conclusion

I’ve used this approach on my personal website, and here’s what I can say about it:

  • The fact to have a two part declaration has been a bit confusing at first, but I got the hang of it rapidly. It’s just that when I’m in my editor, willing to jump to a color definition by clicking a Sass variable, I was used to land on the color code right away. But now I’m first directed to the css variable, and then to the css variables file, then to the color definition.
  • On the code side, it didn’t really change the way I work. When writing code, instead of using a Sass variable representing a color, I use a Sass variable representing a color var. Which means that instead of writing this : background-color: $linksColor;, I write that instead : background-color: $linksVar;. As you can see, not much of a difference.
  • On the browser side though, I really saw a huge benefit. I’ve been able to play with the Css variables values directly from my browser devtools to see changes rendered live on my page. It’s really useful to make design choices, or asses a variable use. I now plan on implementing a dark mode to investigate more on the computed Css output reduction.