7

What I know is that this:

@iterations: 8;
.mixin-loop (@index) when (@index > 0) {

  .my-class-@{index} {
     width: (100% / @index);
  }

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

… Will result in this:

.my-class-8{width:12.5%}
.my-class-7{width:14.285714285714286%}
.my-class-6{width:16.666666666666668%}
.my-class-5{width:20%}
.my-class-4{width:25%}
.my-class-3{width:33.333333333333336%}
.my-class-2{width:50%}
.my-class-1{width:100%}

… Making it the LESS equivalent of:

for (var i = 8; i > 0; -- i) {
  // …
}

My question is: What would the LESS equivalent of:

for (var i = 8; i > 0; -- i) {
  for (var j = 4; j > 0; -- j) {
    // …
  }
}

… Look like?

4 Answers 4

12

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);
Sign up to request clarification or add additional context in comments.

1 Comment

What is the purpose of .i-loop (0) {} ? Tried this code without it and it worked.
1

An Unnested Solution

I'm only offering this as an alternative here for final output code purposes. My answer does not really address nesting of loops directly (as your question is and your own answer found that solution). Rather, it challenges whether nesting is even best to solve the problem you faced.

Assuming a class structure just as you have (say my-class-2-6 for example), you can reduce from 64 output CSS selectors to just 16 by not nesting them and instead using CSS3 attribute selectors (which may not be desirable, depending on target browsers you need to support). Thus this LESS:

@maxi: 8;
@maxj: 8;
@iSelStart: ~'[class^=my-class-';
@jSelStart: ~'[class$=-';
@ijSelEnd: ~']';
.i-loop (@i) when (@i > 0) {

  @{iSelStart}@{i}@{ijSelEnd} {
     width: (100% / @i);
  }
  .i-loop(@i - 1);
}

.j-loop (@j) when (@j > 0) {

  @{jSelStart}@{j}@{ijSelEnd}  {
    height: (100% / @j);
  }

  .j-loop(@j - 1);
}
//stop loops
.i-loop (0) {}
.j-loop (0) {}
//itialize loops
.j-loop(@maxj);
.i-loop(@maxi);

Becomes this CSS:

[class$=-8] {
  height: 12.5%;
}
[class$=-7] {
  height: 14.285714285714286%;
}
[class$=-6] {
  height: 16.666666666666668%;
}
[class$=-5] {
  height: 20%;
}
[class$=-4] {
  height: 25%;
}
[class$=-3] {
  height: 33.333333333333336%;
}
[class$=-2] {
  height: 50%;
}
[class$=-1] {
  height: 100%;
}
[class^=my-class-8] {
  width: 12.5%;
}
[class^=my-class-7] {
  width: 14.285714285714286%;
}
[class^=my-class-6] {
  width: 16.666666666666668%;
}
[class^=my-class-5] {
  width: 20%;
}
[class^=my-class-4] {
  width: 25%;
}
[class^=my-class-3] {
  width: 33.333333333333336%;
}
[class^=my-class-2] {
  width: 50%;
}
[class^=my-class-1] {
  width: 100%;
}

So the example of my-class-2-6 would target the start of the class name my-class-2 giving a width: 50% and target the end of the class name -6 which would give a height: 16.666666666666668%;.

Just a thought for any future users facing a similar situation who are only worried about targeting CSS3 browsers.

Update: Added Protection to not Incorrectly Target

As an after thought, it occurred to me that if you have various types of classes that may have an ending of -1 or -2 etc., then your ending CSS may need to have an additional set of code to help filter for just that class. So the j loop code above would need to have a change to the selector string like so:

@{iSelStart}@{ijSelEnd}@{jSelStart}@{j}@{ijSelEnd}  { /*properties*/}

Which would then output this format of code:

[class^=my-class-][class$=-1] {
  /*properties*/
}

This way it is looking specifically for the my-class- "class" that ends in -1, and would ignore selecting another class like another-class-1 as the original code above would still select. Whether this is an issue or not would purely be related to the design and class naming used in one's site.

2 Comments

Thank you. This is interesting.
FYI--I just added an after thought in a code change for some protection against improper selection that may be relevant in some situations.
0

Old question but maybe it's worth mentioning that Less can now do this easier

Function

.for(@i, @n, @r){@r();._(@i)}
.for(@n, @r)when(isnumber(@n)){.for(0, @n, @r)}
.for(@i, @n, @r)when not(@i = @n - 1){.for((@i + ((@n - @i) / abs(@n - @i))), @n, @r)}

Usage

.for(3, {._(@i) {
  .for(3, {._(@j) {
    item-@{i}-@{j} {
      i: @i;
      j: @j;
    }
  }});
}});

Example: Codepen

Comments

0
.loop(@n: 1, @m: @n, @k: @n * @m) when(@k > 0) {
    .loop(@n, @m, @k - 1);

    @i: `Math.floor((@{k} - 1) / @{m})`;
    @j: @k - @i * @n - 1;

    /*
        @i runs up 1 to @n,
        @j runs up 1 to @m and
        @k runs up 1 to @n * @m

        for example:
    */

    &:nth-child(@{k}) {
        top: 50px * @i;
        left: 100px * @j;
    }
}

/* using: */
.loop(3,4);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.