bizzehdee
bizzehdee

Reputation: 21003

Multiple selectors in loop in LESS

I am using the following code to generate a column layout using LESS CSS:

.columnBuilder (@index) when (@index =< @columnCount) {

  .container_@{columnCount} .grid_@{index}  {
    width: unit(((@baseWidth / @columnCount) * @index)-10, px);
  }

  .columnBuilder(@index + 1);
}

Which gives me an output:

.container_24 .grid_1 {
  width: 69px;
}
.container_24 .grid_2 {
  width: 148px;
}
.container_24 .grid_3 {
  width: 227px;
}

etc...

How would i now create a new less function that would give an output of:

.grid_1,
.grid_2,
....,
.grid_N {
  display: inline;
  float: left;
  margin-left: 5px;
  margin-right: 5px;
}

Where N is defined as @columnCount: 24;, though the column count is not set, it can be changed to any number. I am aware i could create a body for each grid_X would like to avoid it to keep clutter down.

Upvotes: 3

Views: 1539

Answers (2)

ScottS
ScottS

Reputation: 72261

Using :extend() in LESS 1.4+

This seems to accomplish it more elegantly. You first define the initial values you will want extended in a hard coded .grid_1 class (at present, LESS will not extend dynamically generated classes), then add an extender mixin in your loop to extend to that class. Like so:

.grid_1 { //this acts as the "launch point" for extending them all
    display: inline;
    float: left;
    margin-left: 5px;
    margin-right: 5px;
}

.columnBuilder (@index) when (@index =< @columnCount) {
  //we are going to use this class twice, so just calculate it once
  @gridClass: ~'.grid_@{index}';
  //this is your original code except the variable now used for the grid class
  .container_@{columnCount} @{gridClass} {
    width: unit(((@baseWidth / @columnCount) * @index)-10, px);
  }
  //this is your extender feature, which does not do so for the initial .grid_1
  //which was set above as our launch point.
  @{gridClass} {
    .extender() when (@index > 1) {
      &:extend(.grid_1 all);
    }
    .extender() when (@index = 1) {}
    .extender();
  }
  //iterate the loop just as you were doing
  .columnBuilder(@index + 1);
}
//call the loop starting at 1
.columnBuilder(1);

Output is your expected:

.grid_1,
.grid_2,
....,
.grid_N {
  display: inline;
  float: left;
  margin-left: 5px;
  margin-right: 5px;
}

Upvotes: 5

bizzehdee
bizzehdee

Reputation: 21003

As it turns out, LESS has no native support for something like this and will always create multiple blocks of CSS each with its own body, so you need to run a little hack with mixins. I used the following:

.columnBuilderX (@index) when (@index = 1) {

  @isel: ~".grid_@{index}, ";

  .columnBuilderX (@index + 1, @isel);
}

.columnBuilderX (@index, @innerSel) when (@index =< (@columnCount - 1)) {

  @isel: @innerSel + ~".grid_@{index}, ";

  .columnBuilderX (@index + 1, @isel);
}

.columnBuilderX (@index, @innerSel) when (@index = @columnCount) {
  @isel: @innerSel + ~".grid_@{index} ";

  @{isel} {
    display: inline;
    float: left;
    margin-left: 5px;
    margin-right: 5px;
  }

  .columnBuilderX (@index + 1, @isel);
}

Which produced for me:

.grid_1,  .grid_2,  .grid_3,  .grid_4,  .grid_5,  .grid_6,  .grid_7,  .grid_8,  .grid_9,  .grid_10,  .grid_11,  .grid_12,  .grid_13,  .grid_14,  .grid_15,  .grid_16,  .grid_17,  .grid_18,  .grid_19,  .grid_20,  .grid_21,  .grid_22,  .grid_23,  .grid_24 {
  display: inline;
  float: left;
  margin-left: 5px;
  margin-right: 5px;
}

The first mixin is the initial mixin that is called that does not already have an inner selector, the second mixin requires a second param, which is the variable we create in the first, which then runs recursively until we hit our last column as defined by the when clause, where we add our last selector without the comma, and then use the selector list we have built in to apply our CSS too.

If anybody can come up with something simpler than this, please create an answer.

Upvotes: 0

Related Questions