LESS - Create ID by looping through two variables - css

I am trying to create a loop that outputs all of the possible combinations between coordinates -2,-2 to 2,2. Is there any way to do this without creating multiple loops?
Desired Output
#p1x0,#p2x0,#p-1x0,#p-2x0,#p1x1,#p-1x-1,#p-1x1,#p1x-1,#p2x2,#p-2x-2,p2x-2,p-2x2,#p2x1,#p2x-1,#p1x2,#p1x-2,#p-2x1,#p-2x-1,#p-1x2,#p-1x-2,#p0x-1,#p0x-2,#p0x0,#p0x1,#p0x2{}
Current Attempt
#cube-side {
border:red;
}
.create-cubes(#n, #i: -2, #z: -2, #side-sum:#i + #z) when (#side-sum =< #n) {
& when (#i < #z) {
.create-cubes(#n, #i+1);
}
& when (#z < #i) {
.create-cubes(#n, #z+1);
}
#p#{i}x#{z}:extend(#cube-side) {}
}
.create-cubes(4);
Output
#cube-side,
#p-2x-2 {
border: red;
}

There's way to do this w/o any loops at all:
#cube-side {
border: red;
}
-2, -1, 0, 1, 2 {
#p&x&:extend(#cube-side) {}
}
Though for an arbitrary list of values just a nested loop is the simplest solution of course (see for example), e.g. (in "pure Less") something like:
.create-cubes(-2, 2);
.create-cubes(#min, #max) {
.i; .i(#i: #min) when (#i <= #max) {
.j; .i(#i + 1);
}
.j(#j: #min) when (#j <= #max) {
#p#{i}x#{j}:extend(#cube-side) {}
.j(#j + 1);
}
}

Related

LESS mixin and get default value

I have this mixin:
// define variable for later use
.define(#prefix, #var) {
#defined: '#{prefix}_#{var}';
}
.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))
}
// getProperty mixin
.getProperty(#property, #var, #base: true) {
& when not (##var = false) and (#base = true) {
#{property}: ##var;
}
#custom: 'my_#{var}';
& when not (##custom = false) {
.for(##custom);
.-each(#name) {
.define(#name, #var);
& when not (##defined = false) {
.#{name} & {
#{property}: ##defined;
}
}
}
}
}
My variables are like:
#parallax-color:#ffffff;
#my_parallax-color: ~"page-1" ~"page-2";
#page-1_parallax-color:initial;
#page-2_parallax-color:initial;
I call it like:
.getProperty(color, parallax-color);
How to change my mixin when value = initial then generate default color:#ffffff; ?
How to not render when value = inherit for example?

LESS CSS - returning a variable conditionally

I use LESS CSS, and already use the 'return' functionality.
.get-theme-color(#theme) {
#return: ~"#{mdc-theme-#{theme}}";
}
And use it to assign values this:
#var: .get-theme-color(primary)[];
However, I'm trying to return a value selectively using a mixin. I've tried various formats - this is what I'm currently trying to make work - with no success:
.get-property-box(#mask) when (length(#mask) >= 1) and (length(#mask) =< 4) {
#mask-len: length(#mask);
#val1: extract(#mask, 1);
#value: ~"#{val1}";
& when (#mask-len = 2) {
#val2: extract(#mask, 2);
#value: ~"#{val1} #{val2}";
}
& when (#mask-len = 3) {
#val2: extract(#mask, 2);
#val3: extract(#mask, 3);
#value: ~"#{val1} #{val2} #{val3}";
}
& when (#mask-len = 4) {
#val2: extract(#mask, 2);
#val3: extract(#mask, 3);
#val4: extract(#mask, 4);
#value: ~"#{val1} #{val2} #{val3} #{val4}";
}
#return: #value;
}
Here's an alternative version:
.get-property-box(#mask) when (length(#mask) >= 1) and (length(#mask) =< 4) {
#mask-len: length(#mask);
#val1: extract(#mask, 1);
#return: ~"#{val1}";
& when (#mask-len = 2) {
#val2: extract(#mask, 2);
#return: ~"#{val1} #{val2}";
}
& when (#mask-len = 3) {
#val2: extract(#mask, 2);
#val3: extract(#mask, 3);
#return: ~"#{val1} #{val2} #{val3}";
}
& when (#mask-len = 4) {
#val2: extract(#mask, 2);
#val3: extract(#mask, 3);
#val4: extract(#mask, 4);
#return: ~"#{val1} #{val2} #{val3} #{val4}";
}
}
And call it like this:
.mdc-shape(round) {
#mask: 4rem, 5rem;
border-radius: .get-property-box(#mask)[];
}
The output is:
border-radius: 4rem;
I know that the guards are working correctly (the relevant section is reached), but the return value isn't updated.
Anyone got advice as to how I can make this work?

SASS loop to simplify repetitive code

I have this set of repetitive classes (variables names and overall code simplified for demonstration purposes):
&-category01 { background: linear-gradient((nth($colors-category01, 1), nth($colors-category01, 2)); }
&-category02 { background: linear-gradient((nth($colors-category02, 1), nth($colors-category02, 2)); }
&-category03 { background: linear-gradient((nth($colors-category03, 1), nth($colors-category03, 2)); }
&-category04 { background: linear-gradient((nth($colors-category04, 1), nth($colors-category04, 2)); }
The $colors-... bit comes from a map:
$colors-category01: (#ab1b99, #8f017d);
$colors-category02 (#d2544b, #87352f);
How can I simplify this code with a SASS loop?
Remember that variable interpolation is not valid inside a loop or mixin. Also, my real code is more complex than this practical situation.
My goal is to get this as output:
.category01 { linear-gradient(#ab1b99, #8f017d); }
.category02 { linear-gradient(#d2544b, #87352f); }
(etc...)
If all your color category variables have the same number of colors in them, you can create a new variable that is just a list of all the variables with actual values in them and then loop through that new variable with an #each function.
See #each loop with index for more on that.
$colors-category01: (#ab1b99, #8f017d);
$colors-category02: (#d2544b, #87352f);
$colors-category03: (#ffffff, #000000);
$colors-category04: (#f0f0f0, #333333);
$color-categories: $colors-category01, $colors-category02, $colors-category03, $colors-category04;
#each $category in $color-categories {
$i: index($color-categories, $category);
.category0#{$i} {
background-image: linear-gradient(nth($category, 1), nth($category, 2));
}
}
Results in:
.category01 {
background-image: linear-gradient(#ab1b99, #8f017d);
}
.category02 {
background-image: linear-gradient(#d2544b, #87352f);
}
.category03 {
background-image: linear-gradient(#ffffff, #000000);
}
.category04 {
background-image: linear-gradient(#f0f0f0, #333333);
}
Unfortunately if the reality is that your different color categories actually have different numbers of colors in them, then things get a lot more complicated. I can't personally figure out a way you could loop through an indefinite number of values in those maps and chain together the background-image value. (Which is not to say for sure that it can't be done, but it may well end up taking you longer to figure out than the time you'd be saving by using a loop.)
But you could possibly do a bunch of #if statements to cover a reasonable number of possibilities, if you really wanted to.
$colors-category01: (#ab1b99, #8f017d);
$colors-category02: (#d2544b, #87352f);
$colors-category03: (#ffffff, #000000, #2d2d77);
$colors-category04: (#f0f0f0, #333333, #00ff5e, #ffa900);
$color-categories: $colors-category01, $colors-category02, $colors-category03, $colors-category04;
#each $category in $color-categories {
$i: index($color-categories, $category);
.category0#{$i} {
#if length($category) == 2 {
background-image: linear-gradient(nth($category, 1), nth($category, 2));
}
#if length($category) == 3 {
background-image: linear-gradient(nth($category, 1), nth($category, 2), nth($category, 3));
}
#if length($category) == 4 {
background-image: linear-gradient(nth($category, 1), nth($category, 2), nth($category, 3), nth($category, 4));
}
//et cetera
}
}
Outputs:
.category01 {
background-image: linear-gradient(#ab1b99, #8f017d);
}
.category02 {
background-image: linear-gradient(#d2544b, #87352f);
}
.category03 {
background-image: linear-gradient(#ffffff, #000000, #2d2d77);
}
.category04 {
background-image: linear-gradient(#f0f0f0, #333333, #00ff5e, #ffa900);
}

Pass mixin as mixin param in LESS

I have the the following mixin:
.image-ui-wave-pos (#num, #selected:0) when (#selected = 0) {
background-position: -(#image-ui-wave-width * #num) -28px;
}
I'd like to pass it to the following mixin as parameter:
.small-button (#pos-macro, #buttons, #i) when (#i > 0) {
#button: extract(#buttons, #i);
&.#{button} {
.pos-macro (#i);
}
.small-button(#pos-macro, #buttons, #i - 1);
}
as the parameter #pos-macro calling it like this:
.small-button (.image-ui-wave-pos, #wave-buttons);
But it doesn't compile. How to do so?

Generating classes with a loop

I have a list of colors and I want to generate classes using these colors:
CSS
#color1: #b37974;
#color2: #ffa385;
#color3: #ff5500;
#color4: #b2682e;
This is the code i'm using:
Less
.loopingClass(#index) when (#index > 0) {
#ctype: "color#{index}";
.setClass(#color,#cindex) {
.btn-color-#{cindex} {
background-color:#{color} ;
}
}
.setClass(e(##ctype),#index);
.loopingClass(#index - 1);
};
.loopingClass(2);
When I try to compile the code with gulp, I receive "Unrecognised input" error. When I remove background-color: #{color} the error goes away. What is my mistake in this code?
Update:
The correct code is:
.loopingClass(#index) when (#index > 0) {
#ctype: "color#{index}";
.setClass(#color,#cindex) {
.btn-color-#{cindex} {
background-color:#color ;
}
}
.setClass(##ctype,#index);
.loopingClass(#index - 1);
};
.loopingClass(2);
As I already mentioned in comments above the error there is in e function (which does not make any sense there). The correct code would look like this:
#color1: #b37974;
#color2: #ffa385;
#color3: #ff5500;
#color4: #b2682e;
.loopingClass(#index) when (#index > 0) {
#ctype: "color#{index}";
.setClass(#color, #cindex) {
.btn-color-#{cindex} {
background-color: #color;
}
}
.setClass(##ctype, #index);
.loopingClass(#index - 1);
}
.loopingClass(2);
In fact all this can be simplified to just:
#color1: #b37974;
#color2: #ffa385;
#color3: #ff5500;
#color4: #b2682e;
.loopingClass(#index) when (#index > 0) {
.btn-color-#{index} {
#color: "color#{index}";
background-color: ##color;
}
.loopingClass(#index - 1);
}
.loopingClass(2);
More over the whole thing could be even more simple since you don't need to emulate arrays via "indexed variable names" because you can use array directly (unless you need to refer to those vars separately elsewhere):
#colors:
#b37974,
#ffa385,
#ff5500,
#b2682e;
.loopingClass(2);
.loopingClass(#index) when (#index > 0) {
.loopingClass(#index - 1);
.btn-color-#{index} {
background-color: extract(#colors, #index);
}
}
And finally (since I entered "optimizations never end" mode anyway), same thing with a bit of syntactic sugar:
#import "for";
#colors:
#b37974
#ffa385
#ff5500
#b2682e;
.btn-color- {
.for(#colors); .-each(#color) {
&#{i} {background-color: #color}
}
}
where imported for is thefor.

Resources