How to increment a variable in Scss with a for loop? [duplicate] - variables

This question already has answers here:
Creating or referencing variables dynamically in Sass
(7 answers)
Closed 7 years ago.
Pretty sure this isn't possible with Sass/Scss but want to be certain that this is a limitation of Sass rather than my own misunderstanding of the syntax...
I'm trying to create a list of styles where each list item gets a different color assigned from a bunch of variables:
$color1: #FF0000; // Red
$color2: #FFBF00; // Orange
$color3: #FFFF00; // Yellow
$color4: #7FFF00; // Green
$color5: #007FFF; // Light Blue
$color6: #00FFFF; // Cyan
$color7: #0000FF; // Blue
$color8: #7F00FF; // Purple
$color9: #FF00FF; // Magenta
#for $i from 1 through 9 {
a[href^="link#{$i}"] { color: $color#{$i};
}
}
However, the Sass won't compile. I'm thinking it's just not possible to increment the variable name in this manner. Can anyone confirm?

You can't create variable names in a dynamic way, but you can achieve this with even better semantics and flexibility:
$red : #FF0000;
$orange : #FFBF00;
$yellow : #FFFF00;
$green : #7FFF00;
$lightblue : #007FFF;
$cyan : #00FFFF;
$blue : #0000FF;
$purple : #7F00FF;
$magenta : #FF00FF;
$colors: $red $orange $yellow $green $lightblue $cyan $blue $purple $magenta;
#each $color in $colors {
$i: index($colors, $color);
a[href^="link#{$i}"] { color: $color; }
}
UPDATE: In Sass 3.3, you can use a map for less repetition.
$colors: (
red : #FF0000,
orange : #FFBF00,
yellow : #FFFF00,
green : #7FFF00,
lightblue : #007FFF,
cyan : #00FFFF,
blue : #0000FF,
purple : #7F00FF,
magenta : #FF00FF,
);
#each $name, $color in $colors {
a[href^="link#{$name}"] { color: $color; }
}

Related

less function to generate css class

I try to do any less function which will be called to create some classes.
Here is the way I tried :
.makeCssColor{#couleur) {
.coul_#{couleur} {
background-color: fade(~"#{couleur}, 'Fonce'", 15%);
&.open, &:hover {
background-color: ~"#{couleur}, 'Fonce'";
}
.btMod {
background : url('/img/btModEvt_#{couleur}.png') left top no-repeat transparent;
}
}
}
And I try to call it to create the classes :
.makeCssColor("bleu");
.makeCssColor("rouge");
But it generate an error. I don't find the good way to do it... And it bothers me to repeat all these code for each color (there is more than these line code and more thant two colors !).
Can anyone give me a little help ? :)
[edit]
ok, thanks to your help, this code does not generate an error, but there is a mistake in the CSS file :
#marronFonce = #9d5a1e;
.makeCssColor(#couleur) {
.coul_#{couleur} {
.top {
background-color: #couleur, 'Fonce';
}
.mod {
background : url('/img/btModEvt_#{couleur}.png') left top no-repeat transparent;
}
}
}
.makeCssColor(marron);
Generate this into the css file :
.coul_marron .top{background-color:marron,'Fonce'}
.coul_marron background : url('/img/btModEvt_marron.png') left top no-repeat transparent;
So the background color isn't good :
.coul_marron .top{background-color:#9d5a1e}
.coul_marron background : url('/img/btModEvt_marron.png') left top no-repeat transparent;
I need to evaluate #couleur, 'Fonce' : #marronFonce => #9d5a1e.
I tried #{#couleur, 'Fonce'} but it doesn't works...
Fade function takes a colour and a fade percentage, in your case you are passing 2 colours. Pass them one at a time. I also made some adjustments on #couleur since i some cases they don't need to be escaped
.makeCssColor{#couleur) {
.coul_#{couleur} {
background-color: fade(#couleur, 15%), fade(Fonce, 15%);
&.open, &:hover {
background-color: #couleur, 'Fonce';
}
.btMod {
background : url('/img/btModEvt_#couleur.png') left top no-repeat transparent;
}
}
}
when you call the mixin use the below, no need to use quotes
.makeCssColor(bleu);
UPDATE - just pass it in
.makeCssColor(#couleur, #name) {
.coul_#{name} {
.top {
background-color: #couleur;
}
.mod {
background : url('/img/btModEvt_#{name}.png') left top no-repeat transparent;
}
}
}
then when you call it
.makeCssColor(#marronFonce, marron);
OR
other option is you can make a loop, it's more complicated but you can try it. I am using an example I already have on my computer
first define a variable with the colour and names
#sample:
~"0070" '#ebebe7',
~"08x2" '#00247a',
~"01k0" '#92918e';
then loops thru it
.sample-loop ( #l ) when ( #l > 0 ) {
#item: extract( #sample #l );
#code: extract( #item, 1 );
#colour: color(extract( #item, 2 ));
.ext-#{code} {
background-color: #colour;
}
.sample-loop( #l - 1 );
}
and finally call the loop to generate your classes
.sample-loop( 3 );
depending on which version of less you have, the 3 can coded so it is dynamic. If you have older version of less then you have to hard code the length of the variable, or assign the length to a variable so you can use it anywhere

SASS / SCSS: Interpolate variable from string / name

Is it possible to get a variable by name?
I tried building the following function, but it's not working as expected...
#function variable-lookup($variable, $suffix: "") {
$value: null;
#if ($suffix != "" and global-variable-exists($variable+"-"+$suffix)) {
$value: #{$variable+"-"+$suffix};
}
#else if (global-variable-exists($variable)) {
$value: #{$variable};
}
#return $value;
}
Here's an example of how it might be used:
$primary: #000;
$primary-hover: blue;
a {
color: variable-lookup("primary", "base");
&:hover {
color: variable-lookup("primary", "hover");
}
}
The real power would come in when I want to write a bunch of context-specific, shorthand wrapper functions around this "variable-lookup" function.
Any ideas how to achieve this?
Trying to interpolate #{$variable+"-"+$suffix} to give the value primary-base and further trying to get the value of same variable name is not possible. primary-base is already a value and and can't be interpreted as a variable name. That sort of thing could lead to a lot of chaos.
For what you want to accomplish, you are better of using a map and checking for the key in that map
$colours: (
'primary': red,
'primary-base': blue
);
#function variable_lookup($colour, $suffix: '') {
$value: null;
#if ( $suffix != '' and map-has-key($colours, unquote($colour+'-'+$suffix)) ) {
$value: map-get($colours, unquote($colour+'-'+$suffix));
} #else if ( map-has-key($colours, unquote($colour)) ) {
$value: map-get($colours, unquote($colour));
}
#return $value;
}
div {
color: variable-lookup(primary, base);
}
p {
color: variable-lookup(primary);
}
This compiles to the following css
div {
color: blue; }
p {
color: red; }
Your code stored colours as variables but I used those names as keys in maps
This allowed to simulate the checking of variables in your code using the map-has-key method. If that returns true, the key exists and we can get the value which in this case would be the colour using map-get
UPDATED ANSWER
One way to address the issues you raised in your comments would be to define the variables and use them in as values in the map
$primary: #fff;
$warning: yellow;
$colours: ( primary: $primary,
primary-hover: darken($primary, 5%),
secondary: $warning,
secondary-hover: darken($warning, 5%) );
Another way would be to iterate through two lists and map colour to a style
$colours: ();
$list: primary success warning; //map primary to blue, success to green and so on
$shades: blue green yellow;
#for $i from 1 through length($list) {
$key: nth($list, $i);
$value: nth($shades, $i);
$colours: map-merge($colours, ($key: $value));
$colours: map-merge($colours, (unquote($key+'-hover'): darken($value, 5% )) );
}
#debug $colours // (primary: blue, primary-hover: #0000e6, success: green, success-hover: #006700, warning: yellow, warning-hover: #e6e600)
The variable_lookup function remains the same.
Hope this is able to help

LESS : SyntaxError: error evaluating function `lighten`: a.toHSL is not a function

This code
.test { color : lighten( red, 10% ); }
is ok, but
#color : red ;
.test { color : lighten( #color, 10% ); }
results in
SyntaxError: error evaluating function lighten: a.toHSL is not a function
Perhaps due to the missing closing curly bracket }?
#color : red ;
.test { color : lighten( #color, 10% );}
When I test it with the bracket it works great :)

Sass, marking a variable as a string [duplicate]

This question already has answers here:
Sass Interpolation of Mixin, Function, and Variable names
(3 answers)
Closed 8 years ago.
I'm trying to run a loop in Sass to generate the following variables:
$size-xs: 1em;
$size-sm: 1.1em;
$size-md: 1.2em;
$size-lg: 1.3em;
This is what I have so far:
$size-base:1em;
$size-increment:0.1em;
$size-list: "xs","sm","md","lg";
#each $value-size in $size-list {
$size-#{$value-size}:#{$i};
$i:$size-base + $size-increment;
}
The problems I'm having is the $size- is interpreted as a variable, but it's not, it's the root of a set of variables I'd like to generate. Any ideas on how to accomplish this?
Thanks so much for any help!
The error you were getting was because variable names can't be interpolated like that. (You were also trying to use $i before it was defined.)
But you can directly name the elements that will be styled. For example:
$size-base: 1em;
$size-increment: 0.1em;
$size-list: "xs", "sm", "md", "lg";
#each $value-size in $size-list {
$size-base: $size-base + $size-increment;
.#{$value-size} {
font-size: $size-base;
}
}
You can even just output silent placeholders instead of elements, and then extend them when needed.
$size-base: 1em;
$size-increment: 0.1em;
$size-list: "%xs", "%sm", "%md", "%lg";
#each $value-size in $size-list {
$size-base: $size-base + $size-increment;
#{$value-size} {
font-size: $size-base;
}
}
h2 {
#extend %lg;
}
This will only compile the h2 style declaration.
See the example at http://sassmeister.com/gist/a400ded59756a814c47e.

Conditional CSS based on background color variable inside loop

I realise this is a similar question to this Conditional CSS based on background color variable
but I need to do it inside a loop in LESS. If a background colour is too dark I want to generate another class so I can make the text on top lighter but not sure how as I don't think you can use lighten and darken functions with hex colours...?
Here is my LESS http://codepen.io/anon/pen/IlsJE?editors=110
.for(#i, #n) {.-each(#i)}
.for(#n) when (isnumber(#n)) {.for(1, #n)}
.for(#i, #n) when not (#i = #n) {
.for((#i + (#n - #i) / abs(#n - #i)), #n);}
// .for-each
.for(#array) when (default()) {.for-impl_(length(#array))}
.for-impl_(#i) when (#i > 1) {.for-impl_((#i - 1))}
.for-impl_(#i) {.-each(extract(#array, #i))}
// PAs
#pa1: "pa1";
#pa2: "pa2";
#pa3: "pa3";
#pa4: "pa4";
// Colors
#pa1-color: #72afb6;
#pa2-color: #9fad9f;
#pa3-color: #8dd8f8;
#pa4-color: #00567A;
// Setting variables and escaping them
#pas: ~"pa1" ~"pa2" ~"pa3" ~"pa4";
// Define our variable
.define(#var) {
#pa-color-primary: '#{var}-color';
}
// Starting the PA mixin
.pacolors() {
// Generating the loop for each PA
.for(#pas); .-each(#name) {
// After loop happens, it checks what brand is being called
.define(#name);
.#{name} .bg-accent {
background-color: ##pa-color-primary;
}
}
}
.pacolors();
Any help would be appreciated.
You can achieve this by using the built-in contrast function provided by LESS.
// Starting the PA mixin
.pacolors() {
// Generating the loop for each PA
.for(#pas); .-each(#name) {
// After loop happens, it checks what brand is being called
.define(#name);
.#{name} .bg-accent {
background-color: ##pa-color-primary;
color: contrast(##pa-color-primary,
lighten(##pa-color-primary, 100%),
darken(##pa-color-primary, 100%),10%);
/* syntax - contrast(color-for-comparison,
color1 - lighten (100%) is essentially white,
color 2 - darken (100%) is essentially black,
threshold percentage based on which decision is taken
*/
}
}
}
Demo | LESS Function Spec - Contrast
Simplified Version: (Courtesy - seven-phases-max)
// Colors
#pas:
pa1 #72afb6,
pa2 #9fad9f,
pa3 #8dd8f8,
pa4 #00567A;
// Styles
& {
.for(#pas); .-each(#pa) {
#name: extract(#pa, 1);
#color: extract(#pa, 2);
.#{name} .bg-accent {
background-color: #color;
color: contrast(#color, white, black, 10%);
}
}
}
p {padding: 10px}
// ........................................................
#import "https://raw.githubusercontent.com/seven-phases-max/less.curious/master/src/for";
Demo 2