Less CSS Calling Dynamic Variables from a Loop

less css calling dynamic variables from a loop

I have just been trying todo the same thing today with LESS. The solution I came up with is to use a Parametric Mixin to create (define) the variable, see updated exmaple:

@color1:#06A1C0;
@color2:#8F4F9F;
@color3:#ED1D24;
@color4:#5A9283;
@color5:#B38C51;
@color6:#EC008C;
@color7:#8F4F9F;

@iterations: 7;

.define(@var) {
@colorSet: 'color@{var}';
}

.mixin-loop (@index) when (@index > 0) {
color@{index}:hover{
.define(@index);
color: @@colorSet;
}

.mixin-loop(@index - 1);
}
.mixin-loop (0) {}
.mixin-loop(@iterations);

Hope this helps.

Resolving dynamic variables in LESS

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));
}

CSS LESS - add variable in loop

You could move the colors into an array then fetch by index, e.g:

@colors: 'color-item-1' #f00, 'color-item-2' #0f0, 'color-item-3' #00f;

.generate-item(3);

.generate-item(@n, @i: 1) when (@i =< @n) {
.item@{i} {
color: extract(extract(@colors, @i),2);
}
.generate-item(@n, (@i + 1));
}

Dynamically define a variable in LESS CSS

This Cannot Be Done

What you desire to do is not currently possible in LESS. I can think of two possible "workarounds" if you know ahead of time what variable names you want to allow to be used (in other words, not fully dynamic). Then something like one of the following could be done:

Idea #1 (Variable Variables)

.define(@var) {
@fooBar: 0;
@fooTwo: 2;
@fooYep: 4;

@fooSet: 'foo@{var}';
}

.define(Two);
.test {
.define(Bar);
prop: @@fooSet;
}
.test2 {
prop: @@fooSet;
}

Idea #2 (Parametric Mixins)

LESS

.define(@var) {
.foo() when (@var = Bar) {
@fooBar: 0;
}
.foo() when (@var = Two) {
@fooTwo: 2;
}
.foo() when (@var = Yep) {
@fooYep: 4;
}
.foo();
}

.define(Two);
.test {
.define(Bar);
prop: @fooBar;
}
.test2 {
prop: @fooTwo;
}

CSS Output (for both ideas)

.test {
prop: 0;
}
.test2 {
prop: 2;
}

Conclusion

But I'm not sure how useful either would really be, nor do I know if it could have any real application in your actual use case (since you mention the above is not the real use case). If you want a fully dynamic variable in LESS, then it cannot be done through LESS itself.

Consuming Less Vars in a generating for loop

Why not use variable variables ?

@spacing-xsmall: .25rem; // 4px
@spacing-small: .5rem; // 8px
@spacing-medium: 1rem; // 16px
@spacing-medium-large: 1.5rem; // 24px
@spacing-large: 2rem; // 32px
@spacing-xlarge: 2.5rem; // 40px
@spacing-xxlarge: 4rem; // 64px

@sizes: xsmall, small, medium, medium-large, large, xlarge, xxlarge;

.init-spacing(@i) when (@i > 0) {

@size: extract(@sizes, @i);
@space: ~"spacing-@{size}";

.margin-@{size} { margin: @@space }

.padding-@{size} { padding: @@space; }

.init-spacing(@i - 1);
}

.init-spacing(length(@sizes));

I got (with a preview)

.margin-xxlarge {
margin: 4rem;
}
.padding-xxlarge {
padding: 4rem;
}
.margin-xlarge {
margin: 2.5rem;
}
.padding-xlarge {
padding: 2.5rem;
}
.margin-large {
margin: 2rem;
}
.padding-large {
padding: 2rem;
}
.margin-medium-large {
margin: 1.5rem;
}
.padding-medium-large {
padding: 1.5rem;
}
.margin-medium {
margin: 1rem;
}
.padding-medium {
padding: 1rem;
}
.margin-small {
margin: 0.5rem;
}
.padding-small {
padding: 0.5rem;
}
.margin-xsmall {
margin: 0.25rem;
}
.padding-xsmall {
padding: 0.25rem;
}

SASS Dynamic variable inside @for loop

You cannot interpolate to call a variable with SASS. You best bet is to use maps, which work like arrays. Here's a good reference: https://webdesign.tutsplus.com/tutorials/an-introduction-to-sass-maps-usage-and-examples--cms-22184

Use dynamic SASS function names inside a loop

Use the function call to call yours:

@function size-1() {
@return #{ ( 8 / 16 ) }rem;
}
@function size-2() {
@return #{ ( 16 / 16 ) }rem;
}
@function size-3() {
@return #{ ( 24 / 16 ) }rem;
}
@function size-4() {
@return #{ ( 32 / 16 ) }rem;
}

...

@for $i from 1 through 18 {
.mt-#{$i} {
margin-top: call(size- + $i);
}
}

(Tested in: https://www.sassmeister.com/ )

EDIT: Another way with less functions:

@function size($num) {
@return #{ ( $num/2) }rem;
}

@for $i from 1 through 18 {
.mt-#{$i} {
margin-top: size($i);
}
}

Dynamic class names in LESS

I don't think you're far off. What I've done is create a second variable inside the mixin, called @index2. All this does is find the '920px minus @index' value that you're looking for:

@index2 = (920-@index);

this is then appended to the class name:

(~".gs@{index}-@{index2}") {

This is the complete loop:

.loopingClass (@index) when (@index > 160) {
@index2 = (920-@index);
// create the actual css selector, example will result in
// .myclass_30, .myclass_28, .... , .myclass_1
(~".gs@{index}-@{index2}") {
// your resulting css
width: (@index/20+1)*@col;
}
// next iteration
.loopingClass(@index - 60);
}
// "call" the loopingClass the first time with highest value
.loopingClass (@iterations);

In order to get just the set you are looking for (gs220-700 to gs700-220), just change @iterations to equal 700.

Worth noting that currently, this will create the classes in the reverse order of how you specified them in the question.



Related Topics



Leave a reply



Submit