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.
Related
This question already has answers here:
Immediate Child selector in LESS
(5 answers)
Closed 4 years ago.
I have a css output and I want to write this code in .LESS I see it uses the ">" to target down.
how do you write that in less to target with ">"
.clever-menu ul.clever-mega-menu > li.level0.active > a span
This is the equivalent in LESS
.clever-menu {
ul.clever-mega-menu {
> li.level0.active {
> a span {
color: black;
}
}
}
}
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
I am trying to realize a modular approach to text sizing using the following starting variables:
#font-size: 1.7rem;
#line-height: 1.414;
I would like to write a mixin that would create this result but have not quite fully grasped LESS yet:
h4 {
font-size: #font-size * #line-height;
}
h3 {
font-size: (#font-size * #line-height) * #line-height;
}
h2 {
font-size: ((#font-size * #line-height) * #line-height) * #line-height;
}
h1 {
font-size: (((#font-size * #line-height) * #line-height) * #line-height) * #line-height;
}
You have an array with your selectors - #elements.
Then you get the length of #elements - it will be used as iterator through an array.
Then the loop starts. It has the name set-font-size. In Less loops are recursive mixins. This mixin takes some parameters and calls itself until some condition is correct. In this example, it works while #_i > 0. Every time it calls itself, the value of #_i decreases.
Inside mixin (or loop) you get current element from array by calling extract(#array, #index) command. Then you set the font size to your selector. Evry time mixin call itself, the value of font-size is increased #_font-size * #_line-height.
That's all :)
Codepen DEMO.
Less:
#elements: h1, h2, h3, h4;
#iterations: length(#elements); // lehgth of #elements
#font-size: 1.7rem;
#line-height: 1.414;
.set-font-size(#_i, #_elements, #_font-size, #_line-height) when (#_i > 0) {
#selector: extract(#_elements, #_i);
#{selector} {
font-size: #_font-size;
}
.set-font-size(#_i - 1, #_elements, #_font-size * #_line-height, #_line-height);
}
.set-font-size(#iterations, #elements, #font-size, #line-height);
Css output:
h4 {
font-size: 1.7rem;
}
h3 {
font-size: 2.4038rem;
}
h2 {
font-size: 3.3989732rem;
}
h1 {
font-size: 4.8061481rem;
}
Simple question: I don't understand what the Advanced arguments do in Less CSS, as per http://lesscss.org/features/#mixins-parametric-feature-advanced-arguments-and-the-rest-variable . I've battled to get my head around how it's explained there.
I understand this:
.mixin(#a: 1) {
But I don't understand the following two, where the ... is introduced:
.mixin(...) { // matches 0-N arguments
.mixin() { // matches exactly 0 arguments
.mixin(#a: 1) { // matches 0-1 arguments
.mixin(#a: 1; ...) { // matches 0-N arguments
.mixin(#a; ...) { // matches 1-N arguments
.mixin(#a; #rest...) { // #rest is bound to arguments after #a
// #arguments is bound to all arguments }
I'm learning Less because I'm very keen on bootstrap, but this puzzled me.
Thank you very much!
Well, okay you should also read http://lesscss.org/features/#mixins-parametric-feature-pattern-matching.
In Less only mixin that match the number of arguments of the caller are compiled. Notice also that when two or more mixins match, all of them are compiled into CSS.
When you mixin got one argument, like that shown below:
.mixin(#a) {}
Only callers with one argument match and will be compiled: .mixin(3); or .mixin(1) and so on. But NOT .mixin() or .mixin(1,2,3)
When you set a default value for the first argument, for instance 3, as shown below:
.mixin(#a: 3) {}
Now not only calls with 1 argument match, but also calls with zero arguments:
.mixin(#a: 3) {property: #a;}
p{ .mixin();}
outputs:
p {
property: 3;
}
Now take a look to the special ... argument, that argument matches any number of arguments. So .mixin(...) will match and get compiled the following callers .mixin(), .mixin(1) and .mixin(1,2,3,4).
When you prepend a name (including the #) to the ... argument the values will be assigned to a variable with that name:
.mixin(#listofvariables...) {
p: #listofvariables;
}
p {
.mixin(one; two; three);
}
outputs:
p {
p: one two three;
}
Notice that ... assigns the arguments to a list, which can be manipulated with the list functions too.
An mixin such as .mixin(#a; ...) is a variant of the preceding two use cases. This mixins requires a first argument set, followed by zero or any other arguments.
#arguments is a special variable that contains a list of all argument of the mixin:
.mixin(#a; #b) {p1: #arguments; p2:extract(#arguments,2); p3:#b;}
p {.mixin(1; 2);}
outputs:
p {
p1: 1 2;
p2: 2;
p3: 2;
}
So the #arguments variable can be used in any mixin and does not require an ... argument.
What would a caller for a mixin like this look like? .mixin(#a; ...)
could it be something like this: .mixin(#a,53px); ? How does it
determine where the 53px goes to?
The 53px is not assigned to a variable, but it is the second item of the #arguments list. You can get it by extract(#arguments,2).
An use case for the .mixin(#a; ...) {} can be to assign a property always when .mixin() regardless the number of arguments, example:
.mixin(#a; ...) { color: #a;}
.mixin(#a) { background-color: contrast(#a); width:100%;}
.mixin(#a; #b;) { background-color: contrast(#a); width:#b;}
div {
.mixin(red);
}
div.small {
.mixin(red,50%);
}
outputs:
div {
color: red;
background-color: #ffffff;
width: 100%;
}
div.small {
color: red;
background-color: #ffffff;
width: 50%;
}
notice that the .mixin(#a; #rest...) {} assigns 35px the first item of the #rest list. And so the following Less code:
.mixin(#color,#padding...) {
color: #color;
padding: #padding
}
div {
.mixin(red; 10px; 20px; 5px; 5px);
}
outputs:
div {
color: red;
padding: 10px 20px 5px 5px;
}
I am trying to generate a number of classes in a loop based on a number of pre-defined variable snippets.
I have a variables.less document that I am importing at the top of this less file containing my color variables. I then want to generate matching classes for these, but I am unable to get less to compile the variable.
My code:
.loop-class(~"primary", ~"success", ~"info", ~"warning", ~"danger";);
.loop-class(#list, #index: 1) when (isstring(extract(#list, #index))) {
#status: extract(#list, #index);
.button-#{status} {
color: ~'#button-#{status}';
}
.loop-class(#list, (#index + 1));
}
Which compiles to:
.button-primary {
color: #button-primary;
}
.button-success {
color: #button-success;
}
etc etc
As you can see, I get the variable name to concatenate correctly, but I can not get it to resolve, so I'm guessing that LESS has already done it's variable compilation before getting to this function?
I have already tried moving the variables into this document, as well as wrapping the variables in a mixin and adding that inside the .loop-class, but neither of these seemed to help.
I also tried something like:
#status: extract(#list, #index);
#compileClass: ~'#button-#{status}';
.button-#{status} {
color: #compileClass;
}
where I am saving the variable in a another one and then referencing that, but it yields the same result.
I looked at less css calling dynamic variables from a loop and tried implementing that as follows:
.loop-class(~"primary", ~"success", ~"info", ~"warning", ~"danger";);
.define(#var) {
#fallback: ~'#button-#{var}';
}
.loop-class(#list, #index: 1) when (isstring(extract(#list, #index))) {
#status: extract(#list, #index);
.button-#{status} {
.define(#status);
color: ##fallback;
}
.loop-class(#list, (#index + 1));
}
But that gave me the error that ##button-danger (last in the index) is undefined, so it still can't resolve the variable.
Is it obvious to you guys what I'm doing wrong?
Thanks for your help!
Missing Brackets
You are missing a set of needed brackets to resolve the variable:
LESS
//imported from another file
#button-primary: cyan;
#button-success: green;
#button-info: orange;
#button-warning: yellow;
#button-danger: red;
//in your mixin file
.loop-class(~"primary", ~"success", ~"info", ~"warning", ~"danger";);
.loop-class(#list, #index: 1) when (isstring(extract(#list, #index))) {
#status: extract(#list, #index);
.button-#{status} {
color: ~'#{button-#{status}}'; /* two more brackets needed */
| |
here here
}
.loop-class(#list, (#index + 1));
}
CSS Output
.button-primary {
color: #00ffff;
}
.button-success {
color: #008000;
}
.button-info {
color: #ffa500;
}
.button-warning {
color: #ffff00;
}
.button-danger {
color: #ff0000;
}
Cleaner More Friendly Code
Also, as a matter of less cluttered and more user friendly code, you can remove your multiple string interpolations needed for the mixing call by changing isstring to iskeyword in your mixin:
.loop-class(primary, success, info, warning, danger;); /* cleaner code on call */
.loop-class(#list, #index: 1) when (iskeyword(extract(#list, #index))) {
#status: extract(#list, #index);
.button-#{status} {
color: ~'#{button-#{status}}';
}
.loop-class(#list, (#index + 1));
}