DEV Community

Cover image for CSS Custom Properties (vars) with SASS/SCSS, a practical architecture strategy

CSS Custom Properties (vars) with SASS/SCSS, a practical architecture strategy

Felippe Regazio on April 17, 2020

If you dont know about CSS Custom Properties yet, you really should learn about. I particularly prefer to use CSS custom properties instead of SASS...
Collapse
 
ryzhov profile image
Aleksandr N. Ryzhov

Hi, you say about prefix to avoid conflict => "and in the case of CSS Custom Properties, also add a prefix to avoid conflicts", point me please where and how it can happen ?

Thanks for article, very useful,
Alex

Collapse
 
felipperegazio profile image
Felippe Regazio

There are some cases:

  1. If you have a very large codebase, you can use those prefixes as namespaces, to avoid name conflict on your own codebase.

  2. If you load a CSS Lib that uses a variable name with same name as yours, that also would be a problem.

  3. If your Styles will be used along a very large or distributed application, you dont know what kind of code already lives there, so better to use prefixes to keep everybody safe,

Collapse
 
ryzhov profile image
Aleksandr N. Ryzhov

It's clear now,
Thanks a lot

Collapse
 
geissht profile image
geissht

this is super super helpful, thank you Felippe!

Collapse
 
bfintal profile image
Benjamin Intal • Edited

This is exactly what I'm trying to do. This is great to keep your styles DRY.
I've extended this further so that the fallback values would automatically be placed by the cssvar() mixin. Perhaps others may find this useful, here's my modification:

Add this at the top to hold all the styles:

$_cssvars: ();
Enter fullscreen mode Exit fullscreen mode

Add this at the start of the cssvars() mixin to gather all the styles:

$_cssvars: map-merge( $_cssvars, $css_variables ) !global;
Enter fullscreen mode Exit fullscreen mode

Then finally, change the output of the cssvar() mixin:

@return var(--#{$prefix}-#{$name}, map-get( $_cssvars, $name ) );
Enter fullscreen mode Exit fullscreen mode

Afterwards the cssvar() mixin would automatically add the fallback value, you'll get this:

height: cssvar(btn-height, 40px);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
felipperegazio profile image
Felippe Regazio

holy shit thats awesome, thanks!

Collapse
 
cawabunga profile image
Emil

That's exactly what I thought. Great article as well as good comment. Thanks both!

Collapse
 
bytrangle profile image
Trang Le

Thank you. I like both SASS and CSS custom properties, and I'm glad to have found a good approach to use both. However, when importing config and helpers partials into the main stylesheet, can you get auto-correct for the cssvar function?

Collapse
 
felipperegazio profile image
Felippe Regazio

hey thanks Trang! ^^
sorry, but i didn't got, what do you mean with "auto-correct"?

Collapse
 
bytrangle profile image
Trang Le • Edited

I mean: cssvar() is a function to retrieve a CSS custom property.

Say you declare cssvar() in config/_helpers.scss.

Then you import the helpers module into your global stylesheet, e.g. global.scss.

Then you call cssvar():

body {
  color: cssvar(color-primary, ui); // Expected output: color: var(--ui-color-primary)
}
Enter fullscreen mode Exit fullscreen mode

This would require me to remember what name I gave to my primary color variable, and what prefix I used, right? This means I'd need to go back to helpers module to check that. Otherwise, I may pass parameters that return non-existing CSS variables.

Do I make sense?

Thread Thread
 
felipperegazio profile image
Felippe Regazio

ah yah! that makes total sense. there are some ways to overcome this problem, i think my choice would be:

declare an outer scope sass var that defines a section/file css var prefix. that var can also be overrided, so in the header, main file or config file of any module that you want, you can set yoru prefix once, than all the cssvar functions will readit. this has some flaws also in a manner that you will have to pay attention in how to set your module $prefix in a cascade style.

would be something like:

Collapse
 
tvld profile image
Tom • Edited

In this line, I have brain-cracker:

$other-color: #0f0;
@debug opacify($other-color, 0.3); // #works

// but:
$primary-color: var(--v-primary-base);

.my-color {
color: $primary-color; // while this works
}

@debug opacify($primary-color, 0.3); // this fails with '$color: --v-primary-base is not a color.'

Collapse
 
felipperegazio profile image
Felippe Regazio

i think the problem is that sass is trying to reach a --v-primary color in a literal way, but --v-primary is not a sass var or value, so the sass function will try to literally act on a --v-primary notation, not its value.

a solution can be declare your css vars from a scss map, then you always have the values as css vars ou sass properties always when needing:

@use "sass:map";

$colors: (
    "primary-color": #fb7988,
    "secondary-color": #4ecdc4,
    "hover-color": #f1f1f1,
    "stripe-color": #f1f1f1,
);

:root {
    @each $color, $value in $colors {
        --#{$color}: #{$value};
    }
}

.op {
    opacity: opacify(map.get($colors, 'primary-color'), .3);
}
Enter fullscreen mode Exit fullscreen mode

you can also take a look on this post:
codyhouse.co/blog/post/how-to-comb...

Collapse
 
giorgosk profile image
Giorgos Kontopoulos 👀 • Edited

The topic is presented very well and your helper functions are very handy. I am going to use them on my next project, thanks.

Collapse
 
felipperegazio profile image
Felippe Regazio

✌️ 😃

Collapse
 
jagoqui profile image
jagoqui

Thanks, very interesant post, now to practice to have a cleaner and more maintainable code!.
Greetings from Colombia.