The @extend directive lets you share a set of CSS properties from one selector to another.
The @extend directive is useful if you have almost identically styled elements that only differ in some small details.
The following Sass example first creates a basic style for buttons (this style will be used for most buttons). Then, we create one style for a "Report" button and one style for a "Submit" button. Both "Report" and "Submit" button inherit all the CSS properties from the .button-basic class, through the @extend directive. In addition, they have their own colors defined
which will be compiled as
By using the @extend directive, you do not need to specify several classes for an element in your HTML code, like this: <button class="button-basic button-report">Report this</button>. You just need to specify .button-report to get both sets of styles.
The @extend directive helps keep your Sass code very DRY.
Any object-oriented programming language, the @extend directive can be chained. That is, you can extend a class that extends another class:
.button-base {
margin: 2px;
radius: 2px;
}
.error-button {
@extend .button-base;
background-color: red;
}
.menu-button-error {
@extend .error-button;
}
which is transpiled to
.button-base, .error-button, .menu-button-error {
margin: 2px;
radius: 2px;
}
.error-button, .menu-button-error {
background-color: red;
}
Unlike most object-oriented programming languages, which only allow inheritance from a single base class, you can use @extend as many different classes as you need to:
.button-base {
margin: 2px;
radius: 2px;
}
.error-base {
background-color: red;
}
.error-button {
@extend .button-base;
@extend .error-base;
}
Notice that it isn't necessary for the child class to contain any properties of its own. The example above results in the following CSS:
.button-base, .error-button {
margin: 2px;
radius: 2px;
}
.error-base, .error-button {
background-color: red;
}
Only single selectors can be extended. You can't, for example, extend p.test. But you can use the @extend directive can be used to inherit styles from any single selector, no matter how complex. Selectors like p.error and pseudo-classes like :first-child work just fine. The syntax is the same:
li:first-child {
color: red;
}
.link-list {
@extend li:first-child;
}
which transpiles to
li:first-child, .link-list {
color: red;
}
Did you notice that in all the examples above, the base class, the one that's called by the @extend directive, is included in the resulting CSS? This is different than the behavior or mixins, which are only output when they're called with the @include directive.
Sass provides a mechanism for excluding the base class from the output via the placeholder selector, %. Simply add a % symbol before the name of the elector and it won't be included in the output:
%button-base {
margin: 2px;
radius: 2px;
}
.error-button {
@extend %button-base;
background-color: red;
}
This results in the following CSS output
.error-button {
margin: 2px;
radius: 2px;
}
.error-button {
background-color: red;
}
Of course, this isn't the most efficient CSS since the .error-button selector is used twice. But the example is just that, an example. In a real project, it probably wouldn't make sense to declare the placeholder unless you were going to use it more than once.
The current version of the Sass compiler can't efficiently extend classes inside directives such as @media unless the base class is also inside the directive, so at least for the time being-referencing a base class outside the directive will fail. You can reference classes within the context of the directive, however, so this works fine:
@media print {
.text {
font-family: Sans Serif;
}
p {
@extend .text;
color: black;
}
}
and results in the following CSS
@media print {
.text, p {
font-family: Sans Serif;
}
p {
color: black;
}
}