A Deeper Look at LESS Mixins

Our discussion about LESS continues–this time we’re going to look into LESS mixins. With mixins we can define a group of style declarations once and then reuse them throughout the stylesheet. It helps keep our code DRY as well as producing CSS in a more efficient way, particularly when dealing with complex CSS3 syntax. LESS provides different types of mixins with their very own purpose; they can be straight-forward mixins, or they can work as a (sort of) function. Nonetheless, before we dig deep down into the subject, let’s begin with the basics of how a LESS mixin works, shall we?

Tutorial thumbnail created by Paul Slowinsky from the Noun Project.

The Mixins

LESS always tries to keep its syntax and features so that it closely mimics CSS. Hence a mixin in LESS is declared in the same way as we declare a CSS style rule using a class or an ID selector. Both of the following examples are valid LESS mixins:

.border {
    border: 1px solid #ccc;
}
#shadow {
    -webkit-box-shadow: 3px 3px 3px 0 rgba(0,0,0,0.2);
    box-shadow: 3px 3px 3px 0 rgba(0,0,0,0.2);
}

Then we can include these mixins into another style rule, for instance:

.header {
    .border;
    #shadow;
    color: #000;
}

When compiled, you will have the style declarations from both mixins output within the.header style rule.

.header {
    border: 1px solid #ccc;
    -webkit-box-shadow: 3px 3px 3px 0 rgba(0, 0, 0, 0.2);
    box-shadow: 3px 3px 3px 0 rgba(0, 0, 0, 0.2);
    color: #000;
}

Nested Mixins

As you’ve seen above, LESS mixins and (class and ID) selectors appear the same; a LESS mixin is not defined with a special directive like the $ which you’ll find in Sass. LESS gives more flexibility in terms of creating and applying mixins, and it allows us to reuse a nested selector as a mixin as well. Bootstrap uses this approach to construct its gradient mixins

Now, let’s take our previous .border and extend it with a couple of nested selectors, this way:

.border {
    border: 1px solid #ccc;
    .bottom {
        border-bottom: 1px solid #ccc;
    }
    .top {
        border-top: 1px solid #ccc; 
    }
}

Assuming you would like to apply the border bottom style you would first need to use the .border, then follow it with the .bottom selector. You can use the nested selector using a > combinator (the same way as we do to select direct child elements in CSS) a space combinator, or compounding the two selectors.

/* space combinator */
.header {
    .border .bottom;
}
/* space combinator */
.header {
    .border > .bottom;   
}
/* compounding two selectors */
.header {
    .border.bottom; 
}

All the above methods will result in the same output:

.header {
    border-bottom: 1px solid #ccc;
}

Parametric Mixins

LESS mixins can also be extended into sort of functions by which they accept one or more parameters, hence being called Parametric Mixins. Through these parameters you are able to customize the mixin output in accordance with what’s passed through the parameters.

.border(@border-width; @border-style; @border-color) {
    border: @border-width @border-style @border-color;
}

The above code snippet shows our previous .border mixin has now turned into a Parametric Mixin with three parameters. Now we are able to customize the border property values, namely the border-width, the style, and the color, for instance:

.header {
    .border(2px; dotted; red);
}

The output from the above example would be:

.header {
    border: 2px dotted #ff0000;
}

Parameter Defaults

Please keep in mind that you would always have to set the values of the parameters explicitly when using a .border mixin like the one shown above. If you don’t LESS will throw an error when you try to compile it.

This error occurred because LESS expected the value of the parameters to be set. We can suppress this error by giving the parameter a default value, as follows:

.border(@border-width: 1px; @border-style: solid; @border-color: black) {
    border: @border-width @border-style @border-color;
}

Now, if the parameter’s values are left empty LESS will fall back to the default values.

@arguments

Additionally, LESS has a special variable named @arguments which will pass the default values all together. This is a useful shortcut that makes our code looks neater, particularly when dealing with multiple parameters and lengthy values. Take our previous example: we can replace these lengthy variables @border-width @border-style @border-color to simply@arguments.

.border(@border-width: 1px; @border-style: solid; @border-color: black) {
    border: @arguments;
}

Mixins Guard

In a nutshell, Mixins Guard is the LESS answer to conditional statement. For many entry users however it may take sometime to grasp and get used to the concept of Mixin Guards, since LESS retains the Mixin form to perform conditional statement and uses the when keyword instead of using the if keyword like one that in many popular programming languages.

So, let’s take a very simple example:

.border(@a) when (@a = red) {
    border: 1px solid #000;
}
 
@text-color: red;
 
.header {
    color: @text-color;
    .border(@text-color);
}

The first to the third line of the above code snippet is our Mixin Guard which says: when the.border parameter, @text-color, is set to “red” it should produce border: 1px solid #000;. We use the .border() Mixin into the rule set that follows with the @text-colorincluded as the parameter. The @text-color value is set to “red”, hence when compiled the style declaration from the Mixin should be output as the condition is met.

.header {
    color: #ff0000;
    border: 1px solid #000;
}

Sass uses != operator to negate the condition. In LESS, you can do so with the when notkeyword, like so:

.border(@a) when not (@a = red) {
    border: 1px solid #000;
}

This time the style declaration of .border Mixin will not be generated given the same example as above.

Generating Default Output of Mixin Guard

Previously, we created a Mixin Guard with single evaluation. This Mixin Guard will not generate any output, unless the evaluation returns true. But, what if you still want to generate an output when the inceptive Mixin Guard condition is not met; you want to generate a default output.

To do this, you will need to create a new Mixin right after the first Mixin Guard.

.border(@text-color) when not (@text-color = red) {
    border: 1px solid #000;
}
.border(@text-color) {
    border: 1px solid #f3f3f3;
}

The evaluation goes this way: If the value passed on the @a variable in the initial Mixin is not “red” it will fall to the next Mixin which will produce border: 1px solid #f3f3f3;. In the other language, say, JavaScript, this would equate to some the following code snippet using the if and else keyword.

if (a === "red") {
    document.write("border: 1px solid #000");
} else {
    document.write("border: 1px solid #f3f3f3");
}

When we compile it, we would have the border color to be #f3f3f3 since the variable passed is “red”.

.header {
    color: #ff0000;
    border: 1px solid #f3f3f3;
}

Mixins as a Function

What makes this behavior different from parametric mixins? This type of mixin will return output that is reusable within the style rule where it is included, rather than taking values through parameters. Before we immediately jump on the subject, let’s take a look at how a similar idea is done in JavaScript.

function color() {
    var color = "#000";
    return color;
}
 
function header() {
    var bgColor = color();
    console.log(bgColor);
};

Here we have two JavaScript functions: color() and header(). When executed the color()function will produce the value from the color variable. We then include the color()function into the header() and store the output in a new variable, bgColor, which we are now able to reuse in the header() function scope. 

In LESS, we are also able to do this, limiting the variables’ and mixins’ scope where they can be reused.

.color() {
    @color: "#000";
}
.header {
    .color();
    background-color: @color;
}

The above code snippet resembles our JavaScript precedent. We created a .color() function and included it in the .header() that follows, which is why we are able to use the @color variable for our background-color. The code will give us the following when compiled:

.header {
    color: #000000;
}

Mixins as functions can also contain mixins or parametric mixins, for instance:

.color() {
    .background-color(@a) when (@a = red) {
        background-color: #fff;
    }
}
.header {
    .color();
    .background-color(red);
}

…which will result in the following:

.header {
    background-color: #fff;
}

Final Thought

LESS provides different types of Mixins which allow us to produce CSS smartly. LESS is rather unique in this regard; it adopts programming traits such as a function, whilst retaining the form of CSS syntax. Hopefully this tutorial has helped you grasp how they work.