Unable to set SCSS variable to CSS variable? - css

Consider the following SCSS:
$color-black: #000000;
body {
--color: $color-black;
}
When it is compiled with node-sass version 4.7.2, it produces following CSS:
body {
--color: #000000;
}
When I compile the same SCSS with version 4.8.3 or higher, it produces following:
body {
--color: $color-black;
}
What am I missing? I checked release logs, but could not found anything useful. Also, I wonder if this change is genuine why does it have only minor version change? Should it not be a major release?
Also, what is my alternative? Should I use Interpolation?

Just use string interpolation:
$color-black: #000000;
body {
--color: #{$color-black};
}
Apparently the old behaviour is not intended and violated the language specs of SASS:
CSS variables mixed with SCSS variables don't emit proper CSS in 4.8+
CSS variables aren't properly compiled
Assigning SASS variables to CSS Variables (Custom Properties) no longer works

scss and css
I found a workaround to mapping the scss variables to css variables.
See Terry's answer for better use
Scss:
// sass variable map
$colors: (
color-black: #FFBB00
);
// loop over each name, color
:root {
// each item in color map
#each $name, $color in $colors {
--#{$name}: #{$color};
}
}
Css:
:root {
--color-black: #FFBB00;
}

I had an issue with older sass versions.
Trying to compile a list of variables coming from an array, it would get stuck with the double dash. Here's my solution in case it helps someone
$var-element:'--';
:root {
#each $color in $color-variables {
#{$var-element}#{nth($color, 1)}: #{nth($color, 2)};
}
}

Related

use SCSS to generate both defaults and css variables

I'm implementing a websites style.
For legacy support reasons, I need to support IE11, at least for a while. For workflow and my sanity reasons, I would like to use css variables where possible.
I have looked at this solution, which would generate something that works, but it is quite verbose to use.
My goal is to end up with a hardcoded value, which is overwritten by a CSS variable immediately. This way I can add a default theme for everyone, and different themes (like darkmode) for those browsers that support css variables. Obviously without needing to write all of that myself.
So the idea would be that I can write something like this:
$foo {...?}
:root {
--foo: red;
}
:root.dark {
--foo: black;
}
p {
color: $foo;
}
and it gets transpiled to
:root {
--foo: red;
}
:root.dark {
--foo: black;
}
p {
color: red;
color: var(--foo);
}
Is this possible with scss? I do not want to add some random npm modules or other third party compilers and transpilers to this project to bloat it.
I know of the possibility of adding a polyfill for IE11 that adds support for CSS variables, but most that I've found so far have some form of unfortunate limitation (plus again, they are third party code that I would prefer to avoid if I can). If there is no nice solution using SCSS, that is probably what I will go with.
Here is a quick solution you might want to improve:
Define a map with all your colors:
$colors: ("blue": #0000ff, "red": #ff0000, "green": #00ff00);
Loop over the map to create the css custom properties:
#each $color, $value in $colors {
:root {
--#{$color}: #{$value};
}
}
Create a mixin to output both the fallback and the value.
I've decided to create a mixin that takes 2 params, the css property and the color you want.
#mixin propertyPlusColorValue($property, $color) {
#{$property}: map.get($colors, $color);
#{$property}: var(--#{$color});
}
Then you can use it like this:
.foobar {
#include propertyPlusColorValue(color, "blue");
#include propertyPlusColorValue(background-color, "red")
}
Full code:
#use "sass:map";
$colors: ("blue": #0000ff, "red": #ff0000, "green": #00ff00);
#each $color, $value in $colors {
:root {
--#{$color}: #{$value};
}
}
#mixin propertyPlusColorValue($property, $color) {
#{$property}: map.get($colors, $color);
#{$property}: var(--#{$color});
}
.foobar {
#include propertyPlusColorValue(color, "blue");
#include propertyPlusColorValue(background-color, "red")
}

Is there a way to define SASS variables in a" [data='value'] {}", or only regular CSS variables?

I want to export "$var" like variables defined as "--var" variables from a Scss file to be used in other files with some scss functions such as "darken()", but it says its not a color.
I'm coding a Vue/Vite website and implementing a theme-change button, that will write data at the HTML tag, and use it to define the theme.
<html lang="en" data-theme="dark"> ... </html>
The base.scss looks like this:
[data-theme="dark"] {
--primary: #c6c7df;
--secondary: #c95d63;
--text-light: #e2ebf5;
}
[data-theme="light"] {
--primary: #26298d;
--secondary: #c95d63;
--text-light: #2c3e50;
}
$primary: var(--primary);
$secondary: var(--secondary);
$text-light: var(--text-light);
I can use the "$var"-like variable at the end of the file, but when I use it inside a "darken($primary, 10%)" function, it gives the following error:
Error: $color: var(--primary) is not a color.
I know it's because I defined it as a CSS variable but if I define the variable inside the "[theme] {}" thing, it doesn't get innitialized and throws the error "Undefined variable"
I know it's a niche question, and I could use something like this, but I wish I could just export it as a scss variable.
Thank you very much.
Of course we cannot make a CSS variable lighten or darken. Think about, What will happen to the Name of CSS variable in the output?
So we have to define all CSS variables and assign desired colors, Before using them.
Solution
For this purpose, you can automatically create the list of CSS variables by #each and create a manual function by #function for easy use. This way gives us a standard css output and the best experience in Sass coding.
// Theme defines area:
$theme-colors:(
"primary": #940fe0,
"secondary": #e49f38,
"warning": #ffe600,
"info": #165ad6
);
$darken-percent: 20%;
$lighten-percent: 20%;
// Functions area:
:root {
#each $name, $color in $theme-colors {
$lighten: lighten($color, $lighten-percent);
$darken: darken($color, $darken-percent);
--color-#{$name}: #{$color};
--color-#{$name}-light: #{$lighten};
--color-#{$name}-dark: #{$darken};
}
}
#function cl($name, $color-tone) {
#if not map-get($theme-colors, $name+''){
#error "`#{$name}` is not defined in Colors Theme";
}
#if $color-tone == d {
#return var(--color-#{$name}-dark);
}
#if $color-tone == l {
#return var(--color-#{$name}-light);
}
#else{
#return var(--color-#{$name});
}
}
// Our custom function usage:
// Use 'b' to return Base color. Ex: cl(primary,b)
// Use 'l' to return Lighten color. Ex: cl(primary,l)
// Use 'd' to return Darken color. Ex: cl(primary,d)
.test {
color: cl(primary,b);
color: cl(warning,l);
}
Compiled css result:
:root {
--color-primary: #940fe0;
--color-primary-light: #bf61f4;
--color-primary-dark: #550980;
--color-secondary: #e49f38;
--color-secondary-light: #f0ca92;
--color-secondary-dark: #a06916;
--color-warning: #ffe600;
--color-warning-light: #fff066;
--color-warning-dark: #998a00;
--color-info: #165ad6;
--color-info-light: #6395ef;
--color-info-dark: #0c337a;
}
.test {
color: var(--color-primary);
color: var(--color-warning-light);

Css variables declared in :root block in styles.scss are invalid

In my angular 11 app I am trying to globally use css variables to declare global colors.
In my styles.scss I have:
:root{
--primary : #0b68e8;
--secondary:#ABCFFF;
}
.test-class{
background: var(--primary);
}
When I am applying that class in one of mine components I can see that var was not properly taken from declared variables:
I tried to find any solution , but cant resolve it. Do you maybe know what is wrong here?
try
.test-class{
background: #{var(--primary)};
}
BTW, if you're using sccs, why not use sass variables?
$primary: #0b68e8;
.test-class{
background: $primary;
}

Unable to use CSS Custom Properties (aka CSS Variables) with SASS #if Statement

I'm trying to pass some CSS Custom Properties to a SASS Mixin. I'm able use the variables when applied directly in the styling I want. But when I try to use a variable in an If statement, it doesn't work.
Mixin Example:
#mixin bg-color($hue, $status) {
background: hsl($hue, 50%, 50%); // $hue works as expected
#if $status == 'danger' { // doesn't work!
color: 'red';
} #else if $status == 'warning' { // doesn't work!
color: 'orange';
} #else { // always enters the else branch
color: 'black';
}
}
CSS:
:root {
--hue: 195;
--status: 'default';
}
.demo {
#include bg-color(var(---hue), var(---status));
}
If I manually add the status value to the mixin, it works:
.demo {
#include bg-color(var(---hue), 'danger');
}
Any idea what might be the issue?
UPDATE: As #temani-afif mentioned, this approach isn't possible because SASS files are compiled before CSS variables are used.
If you have some file, where you import all SCSS files, it depends which is imported first and which are imported after.
Make sure that one that you need to be Read by VS is first.
For example i needed to read first my variables, so it have to be first, other way, my code read mixin, and doesnt know yet what is '$blue'.

Using sass lighten functions with variable not working

I am using SASS in my project with
Here if my variables code
:root, [data-theme="default"] {
--text-color: #383143;
}
$text-color: var(--text-color);
i am using that variable with lighten function like bellow,
body {
color: lighten($text-color, 10%);
}
I am getting the following error,
Error: argument $color of lighten($color, $amount) must be a color
on line 10 of assets/scss/base/typography.scss, in function lighten
How can I use lighten function with that variable? I need to use --text-color: #383143; that format for the color switcher purpose.
You can't use SASS variables in CSS variables as those are compiled before CSS is running. To solve this you could move the CSS variable to be defined by SASS, like this
$text-color: #383143;
:root, [data-theme="default"] {
--text-color: #{$text-color};
}

Resources