Extend vs. Mixins in Less

Caryn Farvour (Humphreys)
Vehikl News
Published in
3 min readMay 27, 2014

--

If you’ve ever used Less before, you’ve almost definitely leveraged the power of mixins to DRY up your stylesheets.

Maybe you had some standard button styling like this:

.btn {
background: blue;
color: white;
}

…and you wanted to include those styles in another more specific button.

You can use mixins to easily mix that class into another class, allowing you to reuse those styles without just copying and pasting them:

.round-button {
.btn;
border-radius: 4px;
}

Not so dry after all

This might seem like a win at first, but if you look closely at the compiled CSS you’ll see some space wasting duplication…

.btn {
background: blue;
color: white;
}
.round-button {
background: blue;
color: white;
border-radius: 4px;
}

Notice how the styles from the .btn class were just copied right into the .round-button class?

Standard CSS lets us group selectors, so we actually could’ve written this stylesheet in less lines by hand:

.btn,
.round-button {
background: blue;
color: white;
}
.round-button {
border-radius: 4px;
}

So what’s the deal? If Less is supposed to be so much better than CSS, why doesn’t it intelligently take advantage of important space-saving features CSS offers by default?

Chapter 1.4: Extend

This used to be a legitimate complaint, and one of the big reasons many people chose Sass over Less. But in version 1.4, Less added the extend feature which elegantly solves this problem.

By rewriting our original Less like this:

.btn {
background: blue;
color: white;
}
.round-button {
&:extend(.btn);
border-radius: 4px;
}

…we get this output, which is exactly what we would’ve coded by hand:

.btn,
.round-button {
background: blue;
color: white;
}
.round-button {
border-radius: 4px;
}

Gotchas

Nested selectors

By default, nested selectors are not extended. So this:

.footer {
padding: 20px;
h2 {
color: white;
}
}
.feed {
&:extend(.footer)
}

…compiles to this, skipping the h2 for the .feed class:

.footer,
.feed {
padding: 20px;
}
.footer h2 {
color: white;
}

You can force the compiler to include all nested selectors by adding the all keyword:

.feed {
&:extend(.footer all);
}

…which gives you the output you probably expected:

.footer,
.feed {
padding: 20px;
}
.footer h2,
feed h2 {
color: white;
}

You can also use a specific nested selector:

.feed {
&:extend(.footer h2);
}

Media Queries

extend will only extend selectors within the same media query.

This works:

@media (max-width: 1024px) {
.feed {
padding: 20px;
}
.sig {
&:extend(.feed);
}
}

This doesn’t:

.feed {
padding: 20px;
}
@media (max-width: 1024px) {
.sig {
&:extend(.feed);
}
}

So what about mixins?

Awesome! But if this is so much better, should we ever still use mixins?

Parametric Mixins

extend is king when you just want to share some static styles between multiple classes, but mixins shine when you need to add a set of dynamic styles.

Let’s talk about buttons. Say we have this as a starting point…

.btn {
background: #217a39;
border: 1px solid #0f3c1c;
border-radius: 4px;
color: #fff;

&:hover {
background: #3eb061;
border-color: #165929;
}
}

Which gives a cool little green button with a nice hover effect.

Now what if we want to reuse this button but with a different color? extend really can’t help us at all here, but parametric mixins make it a breeze:

.btn(@color) {
background: @color;
border: 1px solid darken(@color, 15);
border-radius: 4px;
color: #fff;

&:hover {
background: lighten(@color, 10);
border-color: darken(@color, 5);
}
}

Using this mixin, we can define a bunch of different buttons really easily:

.btn-success {
.btn(#18682f);
}
.btn-alert {
.btn(#9b6910);
}
.btn-error {
.btn(#9b261a);
}

Anywhere you’ve been using static mixins, use extend instead for a nice free reduction in file size. Keep the mixins for when you need to pass in parameters.

Originally published at transmission.vehikl.com on May 27, 2014.

--

--

Caryn Farvour (Humphreys)
Vehikl News

UX Designer, UI Developer, PC gamer, bibliophile, board gamer, coffee drinker, painter, photographer, unapologetic smartass.