How to Create Nested Loops with Less CSS

How do I create nested loops with LESS CSS?

Hm, nevermind—Found it myself.

I’m leaving the answer here for posterity’s sake:

@maxi: 8;
.i-loop (@i) when (@i > 0) {

@maxj: 8;
.j-loop (@j) when (@j > 0) {

.my-class-@{i}-@{j} {
width: (100% / @i);
height: (100% / @j);
}

.j-loop(@j - 1);
}
.j-loop (0) {}
.j-loop(@maxj);

.i-loop(@i - 1);
}
.i-loop (0) {}
.i-loop(@maxi);

LESS CSS nested loops for header elements

This mixin will work in LESS 1.6+. The em at the end of the font-size calculation was kicking up an error and is not necessary as em units are already being used in the calculation.

.headers-generator(@n; @i : 1) when (@i =< @n)
{
h@{i} {
font-size: (2em - (@i - 1) * 0.2);
}

.headers-generator(@n; (@i + 1));
}

.headers-generator(6);

How do I create array of classes in LESS with @loop

I don't know much about LESS, so there might be a cleaner solution, but this should at least work.

Using loop, like you tried, but replacing a dot in value with a dash, so selector is correct.

To escape value:

  1. turn index value into a string, using format function (http://lesscss.org/functions/#string-functions--format),
  2. replace dot with dash, using replace function (http://lesscss.org/functions/#string-functions-replace),
  3. assign value after passing it through escape function (http://lesscss.org/functions/#string-functions-e) to strip quotes.

<style type="text/less">
div {
margin: 0;
border: 1px solid black;
background: white;
color: black;
}

@loop-margin-top: 1;
.loop-margin-top (@i) when (@i >= -1) {
@escapedValue: e(replace(%("%s", @i), "\.", "-", "g"));
.margin-top-@{escapedValue} {
margin-top: ~"@{i}rem";
}
.loop-margin-top(@i - 0.5);
}
.loop-margin-top (@loop-margin-top);
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/less.js/3.12.2/less.min.js"></script>

<div class="margin-top-1">
1
</div>

<div class="margin-top-0-5">
0.5
</div>

<div class="margin-top-0">
0
</div>

<div class="margin-top--0-5">
-0.5
</div>

<div class="margin-top--1">
-1
</div>

Build a repetitive selector within a Less loop

I would go about it somehow in this manner:

.generateClasses (@index, @n, @in:"") when (@index > 0) {
@concatenate: "@{in} .repeatedClass";
@selector: ~".staticClass @{concatenate} > .finalStaticClass";
@{selector}{ height: unit(@n,px) };
.generateClasses((@index - 1), (unit(@n) + 10), @concatenate);
}
.generateClasses(0, @n, @in){};

.generateClasses(4, 10px);

Where you pass on to the next loop the concatenated generated classes and each time add another class. The @index is the counter for the loop, and @n is the value that you want to increase.

CSS output:

.staticClass  .repeatedClass > .finalStaticClass {
height: 10px;
}
.staticClass .repeatedClass .repeatedClass > .finalStaticClass {
height: 20px;
}
.staticClass .repeatedClass .repeatedClass .repeatedClass > .finalStaticClass {
height: 30px;
}
.staticClass .repeatedClass .repeatedClass .repeatedClass .repeatedClass > .finalStaticClass {
height: 40px;
}

Edit - for older versions of Less:

in Less <= 1.3.3, you need to include the individual concatenating loops in a separate role (it is called .test in the example below), that confines the variable. Then you can loop through this, doing something along these lines:

.generateClasses (@index, @n, @in:"") when (@index > 0) {
@concatenate: "@{in} .repeatedClass";
@selector: ~".staticClass @{concatenate} > .finalStaticClass";
.generateClasses((@index - 1), (unit(@n) + 10), @concatenate);
}
.generateClasses(0, @n, @in){};

.test(@i, @ni){
.generateClasses(@i,@ni);
@{selector} {
height: @ni;
}
}

.printClasses(@i:1,@ni:10px) when (@i > 0) {
.test(@i,@ni*@i);
.printClasses(@i - 1,@ni);
}

.printClasses(4);

output CSS will now be:

.staticClass  .repeatedClass .repeatedClass .repeatedClass .repeatedClass > .finalStaticClass {
height: 40px;
}
.staticClass .repeatedClass .repeatedClass .repeatedClass > .finalStaticClass {
height: 30px;
}
.staticClass .repeatedClass .repeatedClass > .finalStaticClass {
height: 20px;
}
.staticClass .repeatedClass > .finalStaticClass {
height: 10px;
}

if you just need to generate a selector once at a time, you can skip the second loop and just call the .test() mixin wherever you need it.

How can I reduce the number of loops to a single helper function?

I think it's just too many possible ways to do this to fit into one answer, so here's just a starting point hint (just one of possible variants):

// usage:

.make-grid(6);

// impl.:

.make-grid(@n-columns) {
.loop(@n-columns);
.loop(@index) when (@index > 0) {
.loop((@index - 1));
.make-grid-column(@index, @n-columns);
}
}

.make-grid-column(@i, @n) {
@value: ((@i / @n) * 100%);
.gd-grid-@{i} {width: @value}
.gd-push-@{i} {left: @value}
.gd-pull-@{i} {right: @value}
.gd-offset-@{i} {margin-left: @value}
// etc.
}

Assuming there's already a zillion Less based grid generation snippets out there it could be quite inspirational to learn certain patterns/tricks from those, see for example.



Related Topics



Leave a reply



Submit