Extending with :extend
Extending adds your selector to a rule that already exists. A mixin copies declarations into every place it is called, while :extend writes the declarations once and lists all the selectors separated by commas. The CSS gets shorter when several classes look the same.
Extending a rule
Describe a base button and extend it in styles/components/buttons.less:
// styles/components/buttons.less
.btn {
padding: 8px 16px;
border-radius: 8px;
}
.btn-primary:extend(.btn) {
color: white;
background: #2563eb;
}.btn,
.btn-primary {
padding: 8px 16px;
border-radius: 8px;
}
.btn-primary {
color: white;
background: #2563eb;
}<style>
.btn,
.btn-primary {
padding: 8px 16px;
border-radius: 8px;
}
.btn-primary {
color: white;
background: #2563eb;
}
</style>
<button class="btn-primary">Publish</button>The .btn-primary selector was added to the .btn rule, and its own declarations stayed in a separate rule. One class in the HTML is enough.
Writing it inside a rule
The same thing can be written inside a rule with &:extend(). This is handier when there are several classes to extend:
// styles/components/buttons.less
.btn {
padding: 8px 16px;
}
.rounded {
border-radius: 8px;
}
.btn-danger {
&:extend(.btn, .rounded);
background: #dc2626;
}.btn,
.btn-danger {
padding: 8px 16px;
}
.rounded,
.btn-danger {
border-radius: 8px;
}
.btn-danger {
background: #dc2626;
}The all keyword
Without extra words :extend matches only exactly the same selector. To capture derived rules too, such as .btn:hover, add all:
// styles/components/buttons.less
.btn {
background: #2563eb;
&:hover {
background: #1d4ed8;
}
}
.link-button:extend(.btn all) {}.btn,
.link-button {
background: #2563eb;
}
.btn:hover,
.link-button:hover {
background: #1d4ed8;
}.link-button received both the normal background and the hover background.
Extend or mixin
:extend | Mixin | |
|---|---|---|
| What reaches the CSS | The selector is added to an existing rule | The declarations are copied |
| Parameters | No | Yes |
| CSS size with many calls | Hardly grows | Grows with every call |
Works inside @media with an outside rule | No | Yes |
In Sass the same job is done by @extend, which is written inside a rule.
Common mistake
:extend looks for the selector in the final CSS. A pure mixin with parentheses never reaches the CSS, so extending it does nothing:
// styles/components/buttons.less
.flex-center() {
display: flex;
align-items: center;
}
.badge:extend(.flex-center) {
width: 32px;
}.badge {
width: 32px;
}Less only prints the warning extend ' .flex-center' has no matches, and the badge stays without centring. For pure mixins use the call .flex-center();, and keep :extend for ordinary classes.