Variable values based on class - sass

Why can't I change a scss variable based on a class? I want the variable to be green when in class dark-mode.
Css:
$test: red;
#mixin darkTheme {
$test: green;
}
.theme-dark {
#include darkTheme();
.test {
background-color: $test;
}
}
Html:
<body class="dark-mode">
<div class="test">test</div>
</body>
How do I accomplish this? What I don't want is 2 variables.

This is because of Variable Scoping.
In Sass, all variables declared outside of a mixin or function will have a global scope and can be referenced in any Sass selector that uses the variable. (source)
This means that any variable value set inside of a mixin or function is only available within that mixin or function, even if the variable was previously set globally.
Switching between different sets of Sass variables
Partials
You could have a partial file for each theme, and import those under each theme's parent class.
_theme-dark.scss
$background-color: #000;
$text-color: #fff;
_theme-light.scss
$background-color: #fff;
$text-color: #000;
_themed-page.scss
body {
background: $background-color;
color: $text-color;
}
theme-styles.scss
.theme-dark {
#import "theme-dark";
#import "themed-page";
}
.theme-light {
#import "theme-light";
#import "themed-page";
}
Maps
Another option is to store the theme values in a map and have a utility function to retrieve the desired value. (source)
_theme-variables.scss
$theme: 'default';
$theme-values: (
'background-color': (
'default': #eee,
'light': #fff,
'dark': #000
),
'text-color': (
'default': #333,
'light': #000,
'dark': #fff
)
);
#function theme-value($key) {
$map: map-get($theme-values, $key);
#return map-get($map, $theme);
}
_themed-page.scss
body {
background: theme-value('background-color');
color: theme-value('text-color');
}
theme-styles.scss
.theme-dark {
$theme: 'dark';
#import "themed-page";
}
.theme-light {
$theme: 'light';
#import "themed-page";
}

Related

How to prefix SASS blocks with a specific scope ID via mixin

Looking to be able to add the app scope id to my sass files when we have multiple apps reusing class names.
That way I can have the following definition:
$app-scope-id: 'appOne';
And then write my SCSS in that app
.blockName{
background: blue;
&__element{
color: orange;
}
}
And call a mixin or something else to just go
#include prefixMixin(){
.blockName{
background: blue;
&__element{
color: orange;
}
}
}
And that render out css like:
.appOne-blockName{ background: blue; }
.appOne-blockName__element{ color: orange }
I'm aware I can use interpolation at the beginning of my block, but was hoping I could keep it cleaner with just a mixin call where necessary and only call it once for an entire SASS file if I wanted.
I don't think it's possible to do what you want with SASS. You could maybe do something like this:
$app-scope-id: 'appOne';
#mixin prefix($selectorType: ".") {
#at-root {
#{$selectorType}#{$app-scope-id}-#{&} {
#content;
}
}
}
blockName {
#include prefix() {
background: blue;
&__element{
color: orange;
}
}
}
Which compiles as:
.appOne-blockName { background: blue; }
.appOne-blockName__element { color: orange; }
But you would still need to include it for each selector that needs the prefix. I'm not sure this can be called "clean" either.

SASS function darken & lighten not working when using object of colors

I am trying to use the darken sass function but when I read from the sass object in my scss module, it thinks the color is actually a string and thus the function fails to parse the variable passed in.
variables.scss
$primary: #ae9fec;
$secondary: #d19ac1;
$theme: (
"primary": ($primary, white),
"secondary": ($secondary, white)
);
Button.module.scss
#each $colorGroup in $theme {
&[data-variant="#{nth($colorGroup, 1)}"] {
background-color: #{nth(nth($colorGroup, 2), 1)}); // this works
&:hover {
background-color: darken(#{nth(nth($colorGroup, 2), 1)}), 10%); // this does not because it thinks its a string. I tried unquote() but that didn't work, still thinks it's a string.
}
}
}
If you remove the interpolation in your selector rules (not the selector itself), it should compile as intended.
Here's a test - and I'm assuming you are nesting the #each loop inside a selector or using #at-root, since base-level rules cannot contain the & character like this - with a .button selector for your ruleset:
/* variables.scss */
$primary: #ae9fec;
$secondary: #d19ac1;
$theme: (
"primary": ($primary, white),
"secondary": ($secondary, white)
);
/* Button.module.scss */
.button {
#each $colorGroup in $theme {
&[data-variant="#{nth($colorGroup, 1)}"] {
background-color: nth(nth($colorGroup, 2), 1);
&:hover {
background-color: darken(nth(nth($colorGroup, 2), 1), 10%);
}
}
}
}
The compiled code looks like this:
.button[data-variant="primary"] {
background-color: #ae9fec;
}
.button[data-variant="primary"]:hover {
background-color: #8a74e4; /* Darkened $primary */
}
.button[data-variant="secondary"] {
background-color: #d19ac1;
}
.button[data-variant="secondary"]:hover {
background-color: #c177ab; /* Darkened $secondary */
}
I also removed the extra parenthesis in the example.

SASS: create name that is unique per-mixin?

I'm creating a mixin called static() that is used inside another mixin to separate the static properties out into placeholders, so that those properties aren't repeated in the output every time a mixin is used. Here's how you would use it in a mixin called button(), for example:
#mixin button($color) {
#include static('button') {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
&:hover {
cursor: pointer;
}
}
background-color: $color;
&:hover {
background-color: mix(black, $color, 15%;
}
}
Here's the code for the static() mixin:
#mixin static($mixin-name, $extend: true) {
// set global $Placeholder-Selectors if it doesn't already exist
$Placeholder-Selectors: () !global !default;
$selector: map-get($Placeholder-Selectors, $mixin-name);
#if $extend == true {
#if $selector == null {
$selector: unique-id();
$Placeholder-Selectors: map-merge($Placeholder-Selectors, ($mixin-name: $selector)) !global;
#at-root %#{$selector} {
#include static($mixin-name, false) {
#content;
};
}
}
#extend %#{$selector};
} #else {
#content;
}
}
The only purpose of the variable $mixin-name is to make sure the declarations of the created placeholder are not overwritten by another placeholder of the same name. My assumption is that the best way to ensure this is to use the name of the mixin itself for the $Placeholder-Selectors' key (since this will be unique to the mixin).
Question:
If that assumption is correct, I don't want to have to type out the name of the mixin I'm using (as in "#include static('button')")...so, in the static() mixin, is there a way to dynamically determine the name of the mixin that static() is being used inside?
Or, is there another way to ensure a placeholder that is unique per-mixin?
No. Sass does not have a way to get any of the names of the mixins used.
That said, you're over-engineering. All you need to do is setup your extend selector outside of the mixin.
%common-button-styles {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
&:hover {
cursor: pointer;
}
}
#mixin button($color) {
color: $color;
#extend %common-button-styles;
&:hover {
background-color: mix(black, $color, 15%);
}
}
If you're jumping through all of these hoops in an attempt to avoid creating duplicate extend only selectors via multiple imports, what you're looking for is called import once. If you're a Compass user, 1.0 includes an extension by default that does this. If not, a quick search will show you a few different ways of implementing such a feature.

sass #if statement based on a class

Can I somehow make use of a static class inside sass to style child elements based on a color variable defined?
Let's say I have a class named red, and I want to define a variable called $color: classname; or $color: #ff0000; based on that class.
If class is red then define an existing variable with a custom color so I can reuse that variable everywhere inside my scss files based on what class I have on the container.
Note that I have a limited number of colors that I need, and can define them inside sass.
Is this what you're looking for?
$colors : (red, blue, green); // array of colors
#each $color in $colors {
.#{$color} {
color: $color;
}
}
The output of the above SASS is
.red {
color: red;
}
.blue {
color: blue;
}
.green {
color: green;
}
If I understand correct your problem You could use a class red and extend this class when you need it.
$red: #FF0000;
.red {
color: $red;
}
.div {
#extend .red;
}
I believe what you are trying to do is:
In an example file called "base.scss":
$red: red;/*this could be a HEX, RGB, whatever*/
#import "other"
In the example file called "other.scss":
div
{
color: $red
}

Passing a list to a mixin in SASS as parameters?

I'm trying to make a SCSS stylesheet easily configurable by defining a set of constants that will be used in a number of mixins and with the Compass library. Ideally, I'd like to be able to do the following:
$item-bgs: linear-gradient(white, black), #ccc;
#mixin some-mixin() {
#include background-with-css2-fallback($item-bgs*);
}
The background-with-css2-fallback is a Compass mixin that accepts up to 10 params. I'm assuming that SASS does not currently support passing a list parameter as the argument list, otherwise Compass would probably use it, but I'm wondering if I can get the $item-bgs list to be the first 2 arguments to the background-with-css2-fallback mixin. Is there a way to do this currently, or is it even planned for SASS in the future?
It may not be supported by SASS natively, but Compass does support passing a list as the first argument to the background-with-css2-fallback mixin. If you look at the source for the mixin, you'll see that it uses a compact function that handles the logic for collapsing the arguments into a single list, whether passed individually or in a single list parameter.
For example, this works fine for me:
#import "compass";
$item-bgs: (linear-gradient(white, black), #ccc);
.test {
#include background-with-css2-fallback($item-bgs);
}
Examples of useing maps as arguments:
Example 1 (list)
#mixin transition($property...){
#if $property {
transition-property: $property;
}
#else {
transition-property: all;
}
transition-timing-function: ease-in-out;
transition-duration: .3s;
transition-delay: 0;
}
.btn {
color: black;
border: 1px solid black;
#include transition(color, border-color);
&:hover {
color: red;
border-color: red;
}
}
Example 2 (Custom params)
#use 'sass:meta';
#mixin example2($args...) {
#each $key, $value in meta.keywords($args) {
#{$key}: #{$value};
}
}
.shape {
#include example2($width:200px, $height:100px);
}
Example 3 (map)
#mixin colors($args:()) {
#if length($colors) > 0 {
#each $key, $val in $args{
.txt-#{$key} {
color: #{$value};
}
.bg-#{$key} {
background-color: #{$value};
}
}
}
}
$colors_map: (
primary: blue,
secondary: green,
accent: red,
light: white,
dark: black
);
#include colors($colors_map);

Resources