Dynamic CSS Classes in LESS

I’m always learning something new or getting better at things. Constant improvement is important to me. I recently began using LESS at work and figured out how to do something cool that I thought was worth documenting and sharing.

If you’re still reading this you probably already have some exposure to both LESS and CSS, so I’ll get right to it.

Repeating CSS

Sometimes you have several CSS rules that are very similar and only have slight variations. This can be kind of annoying to write and maintain, especially if the difference between each rule is predictable and logical.

The scenario that led me to learn this cool feature of LESS was indentation within my HTML table. I had several different levels of indentation that I needed to account for in a table of financial data. It didn’t make sense to use an unordered list, because my data was a table of dollars and sums; so I stuck with a table and created CSS rules I could apply to TD’s where necessary.

Here’s the raw CSS I used:

td.indent-level-1 {
    padding: 0 0 0 18px;
}
td.indent-level-2 {
    padding: 0 0 0 36px;
}
td.indent-level-3 {
    padding: 0 0 0 54px;
}

Functions in LESS

You probably noticed some similarities between the class names and rules, and a relationship between each class name and its rule.

Each class name starts with “indent-level” followed by an integer. Each padding rule is divisible by 18 and, coincidentally, the number in the class name multiplied by 18 equals the right padding I’m after; We’ll use those “coincidences” to our advantage when creating our LESS rules:

td {
    .indent-level(@depth) {
      /* do something */
    }
    .indent-level(1);
 }

“.indent-level(…)” is a LESS function that we will write. Functions in LESS – like any other Procedural Language – allow us to reuse your code. We can also pass variables to your function.

Defining and Using Variables in LESS Functions

So now that we’ve defined our function, and are calling it in our LESS stylesheet, let’s actually do something with it.

td {
    .indent-level(@depth) {
        @className: ~"indent-level-@{depth}";
        &.@{className} {
            padding: 0 0 0 (18px*@depth);
        }
    }
    .indent-level(1);
}

“@className: ..;” is a variable definition where we can use the parameter to dynamically create a string we’ll use as the class name. @{className} is how we use a variable (we’re actually doing that in our className definition too! So, LESS will take our rule and apply the variables to it and “drop it in” in place of our calls to the function.

Now, when we compile our LESS into CSS we get:

td.indent-level-1 {
    padding: 0 0 0 18px;
}

Notice how “(18px*@depth)” becomes “18px”? LESS knows that when we do math on a pixel the result will be a pixel. Also, see that we didn’t have to use “@{depth}” when doing math?

Calling LESS Function Iteratively

We have our LESS Function written and have created our first level of indentation. Great! But we need to create multiple, iterative, levels of indentation. We could call “.indent-level()” multiple times, with the numbers 1-3 hard coded into each call; or we could use a loop in LESS.

Now we can see that if we repeat our call to “.indent-leve(…)” 2 more times, we’ll get all 3 indentations defined thanks to reusable code. Our different levels of indentation will also be evenly spaced from the other levels because they will always be 18px apart!

td {
    .indent-level(@depth) when (@depth > 0) {
        @className: ~"indent-level-@{depth}";
        &.@{className} {
            padding: 0 0 0 (18px*@depth);
        }
        .indent-level(@depth - 1);
    }
    .indent-level(3);
}

Notice the call to “.indent-level(@depth – 1)” is inside our LESS Function. This is how LESS knows to continue looping. It’s not a true loop, it’s more like conditional recursion. Also notice that we only have to actually call the “.indent-level(…)” function 1 time to get things started. And in this case we’re calling it with the largest depth first, and decrementing as we go. Now here’s the result:

td.indent-level-3 {
    padding: 0 0 0 54px;
}
td.indent-level-2 {
    padding: 0 0 0 36px;
}
td.indent-level-1 {
    padding: 0 0 0 18px;
}

Pretty cool! Hopefully this is helpful for you. I’d love to hear how you are using LESS functions, variables, and such to make your CSS easier to maintain. I’m still constantly learning new things myself!

76 thoughts on “Dynamic CSS Classes in LESS

Leave a Reply

Your email address will not be published. Required fields are marked *