On the surface, both of these do the same thing. These will both set the background to red.
SCSS:
body {
$red: #ff0000;
background: $red;
}
CSS:
body {
--red: #ff0000;
background: var(--red);
}
But they are different. There's a CSS Tricks example that talks about some of these differences.
There's a difference not mentioned in the article that tripped me up.
SASS variables compile at runtime, CSS custom properties compile when they're used.
I wanted to send a variable to a mixin, which requires a SASS variable - because it's compiling the mixin before it knows what the CSS custom property refers to.
But I also wanted a dark theme, which is much easier using CSS custom properties.
There is a solution
You an combine them!
$black: #000000;
$white: #ffffff;
:root {
--text-colour: #{$black};
--bg-colour: #{$white};
}
@media (prefers-color-scheme: dark) {
:root {
--text-colour: #{$white}
--bg-colour: #{$black};
}
}
To convert the SASS variable to a CSS custom property you put curly brackets around it, and a hash in front. If you've used template literals in JavaScript it's the same thing, just with a # instead of a $ (because we already have $ in the variable name). It's like someone just went for the next key over on a US keyboard.
Top comments (1)
This is a key insight that is overlooked by many comparisons - and as such one that should be leveraged to the fullest extent.
Following the advice of Don’t do it at runtime. Do it at design time. Sass variables should really be the default. The move to CSS custom properties becomes only really necessary when the value can vary during runtime - as it will with a dynamic theme.
Another example I recently ran across:
where
and later
Now the local override is nice if somewhat orphaned as it assumes that the
flex
utility is being used. And given that width can change at runtime using a CSS custom property seems appropriate.However consider the following:
flex
is captured as amixin
.flex
is tightly coupled toprimary-navigation
anyway and now that's clear from the rule.