Overriding css class variables with LESS

13,260

Let's think about the way LESS compiles for a second. If you want, you can try to run any of this in the https://fiddlesalad.com/less editor.

Here in this example, I've just included some arbitrary colors and a 'background' property to make it easier to understand. In your example when you import base.less, you are really just putting some LESS rules before the ones in your file. So, just to clarify, if we "expand" your import, the file might look like this before its compiled to CSS:

.some-css-class{ 
  @color1: red;
  background: @color1;
}

.some-css-class {
  @color1: purple;
}

What does this output?

.some-css-class {
  background: red;
}

Why? You might say "I've redeclared the color variable so shouldn't it recompile the rules?". However, this is fundamentally not how LESS is designed--its backwards compatible with CSS, so a rule must happen later to override a previous rule. Take this example instead:

.some-css-class{ 
  @color1: red;
  background: @color1;
}

.some-css-class {
  @color1: purple;
  background: @color1;
}

Here is the output you get now:

.some-css-class {
  background: red;
}

.some-css-class {
  background: purple;
}

The rules are split into two outputs, and because the second rule happens later in the cascade, it has a higher precedence--barring this class existing nowhere else, the 'purple' rule will take precedence.

In LESS, you "lazy load" variables -- it will always take the last value found, starting from the inner scope. Thus:

.some-css-class {
  @color1: purple;
  background: @color1;
  @color1: blue;
}

Will output:

.some-css-class {
  background: blue;
}

The unfortunate thing though, however, is if we try to extend your previous rule as a mixin, it resolves the values from each class before pulling them into your new class:

.some-css-class{ 
  @color1: red;
  background: @color1;
}

.some-css-class {
  @color1: purple;
  background: @color1;
  @color1: blue;
}

.another-css-class {
  .some-css-class();
  @color1: orange;
}

Outputs:

.some-css-class {
  background: red;
}
.some-css-class {
  background: blue;
}
.another-css-class {
  background: red;
  background: blue;
}

The ideal way to "override" these values then, is to turn the original ruleset into a parametric mixin:

.some-css-class(@color1, @color2) { 
  background: @color1;
  color: @color2;
}

.another-css-class {
  .some-css-class(red, blue);
}

Finally, your output will look like this:

.another-css-class {
  background: red;
  color: blue;
}

EDIT: Ultimately I recommend, you copy the original rule out of the file (without modifying that file) and alter it to be a mixin in your version. Ultimately you'll end up with the same net amount of CSS as you would if you could extend and override the variables for your new class.

Share:
13,260

Related videos on Youtube

internetzer
Author by

internetzer

As a Software Developer it is always my aim to find simple and elegant solutions to complex problems. Everyday, great minds all over the world are bringing their ideas to life by writing code on a computer. This is the beauty of software development. One is always able to change the world with a great idea. No matter if we are sitting in our offices, in our bedrooms, or in the garden - all we need is right under our fingertips. I love writing code just as much as i love turning off my computer and enjoy the beauty of nature. This is where I am able to recharge my batteries. Sitting on the top of a mountain or on a beach front and letting my eyes and mind wander helps me to focus on what is really important in life. Working with people that share my views and interests is the way I want to do business. Having the mind of an entrepreneur and the heart of a good human being is my key to success. I explore and use state of the art technologies to create tools and services which not only create revenue but actually help people solving their day-to-day problems.

Updated on September 18, 2022

Comments

  • internetzer
    internetzer almost 2 years

    I have a less file which contains a class that defines a few variables for colors:

    .some-css-class{ 
        @color1: #E6E6E6
        @color2: #808080
        /* some other rules follow */
     }
    

    Since this is a 3rd party file I don't wont to change it directly. Instead I created my own less file and imported the 3rd party file. Now I want to override the colors defined in the base file but I don't get it working.

    I tried to override the colors on root level, but this way I am not able to change the variables since they are defined within a class in the base file:

    /* Including base styles */
    @import "base.less";
    
    @color1: #DF007B;
    @color2: #00A855;
    

    So I tried to override the colors within the class, but apparently I am not able to change them this way, as it is not possible to override variables in the same scope (.som-css-class):

    /* Including base styles */
    @import "base.less";
    
    .some-css-class {
        @color1: #DF007B;
        @color2: #00A855;
    }
    

    Any hints on how I am able to override the colors?

    EDIT: It seems that there isn't a solution for this. In my particular case I was looking for a way to override colors in an angularjs module(angular-wizard).

    As i saw now, a pull request to solve this problem already exists: https://github.com/mgonto/angular-wizard/pull/68

  • Harry
    Harry over 8 years
    Nope, I don't think this would work at all because the .some-css-class would still be using old variables + this creates a new class which is not what OP seems to be looking for.
  • internetzer
    internetzer over 8 years
    Like @Harry is pointing out: the base class would still use the old variables. But the base class is used throughout the html of the 3rd party component so unfortunately your solution doesn't work.
  • Marcos Pérez Gude
    Marcos Pérez Gude over 8 years
    Sorry, I put this as a suggestion because if you can use a new classname will be fine and it works, but there are another answer that can be your solution. Sorry for my poor answer :(
  • internetzer
    internetzer over 8 years
    good answer, but I was hoping that there is a better solution. Apparently there isn't :(
  • bazeblackwood
    bazeblackwood over 8 years
    No problem -- I wonder if making a feature request for a future version of LESS would be a good idea?
  • seven-phases-max
    seven-phases-max over 8 years
    Such feature request will barely have any support. Being local is the very purpose of local variables (i.e. if the variables in the above example are supposed to be overriden they are to be moved to some overridable scope. I.e. this is the particular code-base problem, not a language problem at all).
  • bazeblackwood
    bazeblackwood over 8 years
    I tend to agree with you, @seven-phases-max, though a shorthand syntax for injecting variables into an extend statement could be useful to someone else, its sort of a moot point if multi-variadic mixins do the same.