Dynamic class names in LESS

14,881

Solution 1

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.

Solution 2

This whole question was very helpful to me. I just wanted to post the solution to my problem as the way to do it has changed since LESS v 1.4. LESS Changelog

Rather than using the ~ sign, you just write out the portion of the name that you want along with the normal @ and variable name with {} surrounding it. So: #class@{variable}.

For example, my solution using the same sort of loop became such:

/*Total number of passport inserts*/
@numInserts: 5;
/*Total width of the passport foldouts*/
@passportWidth: 300px;
/*Change in passport insert width per iteration*/
@passportWidthDiff: (@passportWidth / @numInserts);
/*"Array" of colors to select from to apply to the id*/
@passportColors: 
blue orange green red yellow 
purple white teal violet indigo;

/*The faux loop the doesn't end up in the final css
@index is the counter
@numInserts is the total number of loops*/
.loopingClass (@index) when (@index <= @numInserts){
   /*This is the created ID with the index appended to it
   You can also do this with classes such as if 
   we had had ".insert@{index}"*/
   #insert@{index}{
      /*Here are our properties that get adjusted with the index*/
      width: (@passportWidth - (@passportWidthDiff * (@numInserts - @index)));
      height: 50px;
      background-color: extract(@passportColors, @index);
      z-index: (@numInserts - @index);
   }
   /*Here we increment our loop*/
   .loopingClass(@index + 1);
}
/*This calls the loop and starts it, I started from 1
since I didn't want to lead a className starting from 0,
But there is no real reason not to.  Just remember to
Change your conditional from "<=" to "<"*/
.loopingClass(1);

And produces the following:

#insert1 {
  width: 60px;
  height: 50px;
  background-color: #0000ff;
  z-index: 4;
}
#insert2 {
  width: 120px;
  height: 50px;
  background-color: #ffa500;
  z-index: 3;
}
#insert3 {
  width: 180px;
  height: 50px;
  background-color: #008000;
  z-index: 2;
}
...
Share:
14,881
R Reveley
Author by

R Reveley

Bristol based user experience/web designer since 2001 who often ends up picking up code too.

Updated on June 09, 2022

Comments

  • R Reveley
    R Reveley about 2 years

    I have the following bit of LESS code working

                @iterations: 940;
                @iterations: 940;
                @col:2.0833333333333333333333333333333%;
                // helper class, will never show up in resulting css
                // will be called as long the index is above 0
                .loopingClass (@index) when (@index > -20) {
                    // create the actual css selector, example will result in
                    // .myclass_30, .myclass_28, .... , .myclass_1
                    (~".gs@{index}") {
                        // your resulting css
                        width: (@index/20+1)*@col;
                    }
                    // next iteration
                    .loopingClass(@index - 60);
                }
                // end the loop when index is 0
                .loopingClass (-20) {}
                // "call" the loopingClass the first time with highest value
                .loopingClass (@iterations);
    

    It outputs our grid system as so:

                .gs940 {
                  width: 100%;
                }
                .gs880 {
                  width: 93.75%;
                }
                .gs820 {
                  width: 87.5%;
                }
                .gs760 {
                  width: 81.25%;
                }
                .gs700 {
                  width: 75%;
                }
    

    etc etc etc

    Now what I want to do is some math to the class names to produce the following classes

                .gs220-700
                .gs280-640
                .gs340-580
                .gs400-520
                .gs460-460
                .gs520-400
                .gs580-340
                .gs640-280
                .gs700-220
    

    etc etc etc

    basically this would be .(@index) - (920px minus @index)

    But I have no idea if this is possible.

  • Michael Cordingley
    Michael Cordingley over 9 years
    I'm curious as to how this would look if we try to pull the repetitive properties out into a single block. In this case, the output that I'm talking about would look like this: #insert1, #insert2, #insert3 { height: 50px; }