Erik
Erik

Reputation: 14750

How to generate classes in LESS?

I need to generate all combinations the following classes:

.b-1-1-1-1 {
  border:1px solid #000;
}
.b-0-1-1-1 {
  border-right: 1px solid #000;
  border-bottom: 1px solid #000;
  border-left: 1px solid #000;
}
.
.
.

I need to use class names as border style likes, is it possible to make it in LESS automatically?

Upvotes: 0

Views: 303

Answers (3)

seven-phases-max
seven-phases-max

Reputation: 11820

(Update: I've been asked to rework my example to a complete snippet - so here we go).

Variant 1

Basically it's the same as in Martin Turjak answer but without inline javascript and with some further makeup:

// usage:

.borders(1px dashed wheat);

div {
    .borders(3px, dotted, red);
}

// implementation:

.borders(@values...) {

    .values(t, 1) {border-top:    @values}
    .values(r, 1) {border-right:  @values}
    .values(b, 1) {border-bottom: @values}
    .values(l, 1) {border-left:   @values}
    .values(... ) {}

    .trbl-(@t, @r, @b, @l) {
        .b-@{t}-@{r}-@{b}-@{l} {
            .values(t, @t);
            .values(r, @r);
            .values(b, @b);
            .values(l, @l);
        }
    }

    .-(@i: 15) when (@i > 0) {
        .-((@i - 1));
        .trbl-(mod(floor((@i / 8)), 2),
               mod(floor((@i / 4)), 2),
               mod(floor((@i / 2)), 2),
               mod(floor((@i / 1)), 2));
    }.-;
}

Variant 2

The magic one, no loops, minified CSS output:

// usage:

.borders(1px, dashed, wheat);

// implementation:

.borders(@values...) {
    0, 1 {
        .b-1-&-&-& {border-top:    @values}
        .b-&-1-&-& {border-right:  @values}
        .b-&-&-1-& {border-bottom: @values}
        .b-&-&-&-1 {border-left:   @values}
    }
}

Upvotes: 3

Martin Turjak
Martin Turjak

Reputation: 21214

You could also just loop through binary numbers instead of a nested loop (makes everything a bit shorter) ... something like this perhaps:

.set-top() when (@t > 0) {
  border-top: 1px solid #000;
}
.set-left() when (@l > 0) {
  border-left: 1px solid #000;
}
.set-right() when (@r > 0) {
  border-right: 1px solid #000;
}
.set-bottom() when (@b > 0) {
  border-bottom: 1px solid #000;
}

.borders(@t:0, @r:0, @b:0, @l:1){
  .b-@{t}-@{r}-@{b}-@{l} {
    .set-top;
    .set-right;
    .set-bottom;
    .set-left;
  }
}

.loop(@i:16) when (@i < 32) {
  .borders(~`(@{i}).toString(2)[1]`,
     ~`(@{i}).toString(2)[2]`, 
     ~`(@{i}).toString(2)[3]`,
     ~`(@{i}).toString(2)[4]`);
  .loop((@i + 1));
}

.loop();

In addition you can again add a check for which properties are set/same and combine them under a combined border property and set the border width/style/color like ScottS shows in his example.

Upvotes: 3

ScottS
ScottS

Reputation: 72261

Doable

This code allows flexibility in setting style and color to the border, the unit value of the width, and defaults to max width of 1 unit (which is px by default). Note that setting the border width values to anything more than 1, the output CSS code is going to begin increasing at a dramatic rate (try running them at just 2, i.e. calling .generateBorderClasses(@t: 2, @r: 2, @b: 2, @l: 2);, and see the results);

.generateBorderClasses(@unit: px, @style: solid, @color: #000, @t: 1, @r: 1, @b: 1, @l: 1) {

.b() when (@check) {
    border: unit(@t,@unit) @style @color;
}

.b() when (@sum = 0) {}

.b() when (@t > 0) and (@sum > 0) and not (@check) {
    border-top: unit(@t, @unit) @style @color;    
}
.b() when (@r > 0) and (@sum > 0) and not (@check) {
    border-right: unit(@r, @unit) @style @color;    
}
.b() when (@b > 0) and (@sum > 0) and not (@check) {
    border-bottom: unit(@b, @unit) @style @color;    
}
.b() when (@l > 0) and (@sum > 0) and not (@check) {
    border-left: unit(@l, @unit) @style @color;    
}

.t-loop (@t) when (@t > -1) {
  .r-loop (@r) when (@r > -1) {
    .b-loop (@b) when (@b > -1) {
      .l-loop (@l) when (@l > -1) {
         @sum: (@t + @r + @b + @l);
         @check: e(`(@{t} == @{r}) && (@{t} == @{b}) && (@{t} == @{l}) ? "true" : "false"`);

        .b-@{t}-@{r}-@{b}-@{l} {
          .b(); 
        }
        .l-loop(@l - 1);
       }
      .l-loop (-1) {} 
      .l-loop(@l);  
      .b-loop(@b - 1);
    }
    .b-loop (-1) {}
    .b-loop(@b);
    .r-loop(@r - 1);
  }
  .r-loop (-1) {}
  .r-loop(@r);  
  .t-loop(@t - 1);
}
.t-loop(-1) {}

.t-loop(@t);

}
.generateBorderClasses();

Still Not Recommended

Personally, I would just have four classes controlling the html (so something like class="bt br bb bl") and then do this:

.bt {
  border-top: 1px solid #000;
}

.br {
  border-right: 1px solid #000;
}

.bb {
  border-bottom: 1px solid #000;
}

.bl {
  border-left: 1px solid #000;
}

MUCH less (pun intended) css code and essentially the same control value in the class assigning of the html.

Upvotes: 1

Related Questions