Last Updated: March 02, 2016
·
4.645K
· griiettner

LESS CSS: Turn one variable part of another variable name

As a JS and PHP coder, I tend to always simplify my code by creating functions that helps me to avoid doing duplicated jobs, so with a function, you get a small piece of code and just reference it later in the middle of the code with parameters and so on.

When we talk about coding with CSS, become obvious that you can not really do this, because CSS is a language based on simplicity and for long time was one the most easy language to work with until recent years, but for more that CSS had evolved, one thing it can not do is work with functions, so in order to do that, we use pre-processor such as LESS, SASS or Stylus, where you can actually code almost in the same fashion as other languages, by setting variables, doing loops, conditional statements and etc...

My favorite one is LESS but I work with SASS and I like how advanced it is.

That being said, lets get to where we are here for... Try to make one LESS variable part of another variable name... Lets set a scenario...

You have a design where you have several containers and inside of each container will have a car manufacture logo with car models and specification... Until there, we have not major problem, but the designer drew a design where each brand has its own background color, font color and you need to embed the logo using css by background image.

In the real world you would write one CSS rule for each brand like

.cars .fordSection {
    background-color: #fff;
    color: #000;
}
.cars .dodgeSection {
    background-color: #000);
    color: #fff;
}
.cars .chevSection {
    background-color: #ff0;
    color: #00f;
}

Well... that was not hard with only 3 brands, but can you imagine if you have 50+ brands and each with their own ruleset? This is what we will try to solve using LESS CSS.

Note: Using SASS or Stylus, is a lot easier, since their structure are more like JavaScrip, where you use "if" and "for"

While searching a way to accomplish this with LESS, I came a cross with several posts and elements that help me put together my puzzle and I`ll start by listing the first one.

By default, LESS does not fave the function "for" or "foreach", but digging on google, I found this fantastic mixing done by Seven Phase Max and you can find it here https://github.com/seven-phases-max/less.curious/blob/master/src/for.less and instructions on how to use here https://github.com/seven-phases-max/less.curious/blob/master/articles/for-each.md and here https://github.com/seven-phases-max/less.curious/blob/master/articles/generic-for.md

LESS MIXIN FOR EACH

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

// .for-each

.for(@array)   when (default()) {.for-impl_(length(@array))}
.for-impl_(@i) when (@i > 1)    {.for-impl_((@i - 1))}
.for-impl_(@i)                  {.-each(extract(@array, @i))}

As you can see in the links provided, you will see that this mixin can do several nice things and seems to be perfect for what I wanted, but it was not enough though... I still need more...

Going back to my google search, I found on stackoverflow a simillar question for what I needed and one of the answers said that such thing could not be accomplished using LESS, however, the person that wrote the answer (ScottS) post some tips that put me in the right direction to find the final piece to my puzzle and you can read about here http://stackoverflow.com/questions/18039082/dynamically-define-a-variable-in-less-css/

DEFINE BRANDS

.define(@var) {
  @fooBar: 0;
  @fooTwo: 2;
  @fooYep: 4;

  @fooSet: 'foo@{var}';
}

.define(Two);
.test {
  .define(Bar);
  prop: @@fooSet;
}
.test2 {
  prop: @@fooSet;
}

OUTPUT

.test {
  prop: 0;
}
.test2 {
  prop: 2;
}

So... putting together both codes we have a nice set of mixins where if will define a variable to loop through and bring the desired result by only referencing one line of code inside your LESS file

FINAL LESS

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

// .for-each

.for(@array)   when (default()) {.for-impl_(length(@array))}
.for-impl_(@i) when (@i > 1)    {.for-impl_((@i - 1))}
.for-impl_(@i)                  {.-each(extract(@array, @i))}


// Brands
@ford : "ford";
@dodge : "dodge";
@chev : "chev";

// BG Colors
@ford-bg : #fff;
@dodge-bg : #000;
@chev-bg : #ff0;

// Colors
@ford-color : #000;
@dodge-color : #fff;
@chev-color : #00f;

// Setting variables and escaping than
@brands: ~"dodge" ~"ford" ~"chev";

// Define our variable   
.define(@var) {
  @brand-bg: "@{var}-bg";
  @brand-color: "@{var}-color";
}

// Starting the mixin
.color() {
    // Generating the loop to each brand
    .for(@brands); .-each(@name) {
        // After loop happens, it checks what brand is being called
        .define(@name);
         // When the brand is found, match the selector and color
        .@{name}& {
            background-color: @@brand-bg;
            color: @@brand-color;
        }
    }
}

Section {
    .color();
}

OUTPUT

.dodgeSection {
  background-color: #000000;
  color: #ffffff;
}
.fordSection {
  background-color: #ffffff;
  color: #000000;
}
.chevSection {
  background-color: #ffff00;
  color: #0000ff;
}

Now you can add as many grand you need on the array and the mixing will generate de appropriate CSS file with all rulesets

NOTE: Codewall is tuning my @ symbols in to link to reference to another user, please disregard the extra code generated by the system. I`m not sure how to use @ symbol without turn into a link... SORRY