SCSS Extend and Mixin

Introduction

@extend can produce more compact CSS than a mixin, but tends to make your stylesheets more difficult to maintain. Below are some examples to help you think through the pros and cons.

The main thing to keep in mind while deciding which of these to use is, “how easy will this be maintain?”

TL;DR

You should use @extend only if:

  • You’ve got an existing class that already has most of what you need.
  • It exists nearby in the same document.
  • It is immediately obvious what you are extending and why.

There are a few exeptions to these rules …but very few.

Extend Example

SCSS:

.row {
  display: flex;
  flex-wrap: wrap;
  margin-right: -15px;
  margin-left: -15px;
}

.new-row {
  @extend .row;
  max-width: 1200px;
}

.another-row {
  @extend .row;
  max-width: 1400px;
}

Compiled CSS:

.row,
.new-row,
.another-row {
  display: flex;
  flex-wrap: wrap;
  margin-right: -15px;
  margin-left: -15px;
}

.new-row {
  max-width: 1200px;
}

.another-row {
  max-width: 1400px;
}

Mixin Example

SCSS:

@mixin row {
  display: flex;
  flex-wrap: wrap;
  margin-right: -15px;
  margin-left: -15px;
}

.new-row {
  @include row;
  max-width: 1200px;
}

.another-row {
  @include row;
  max-width: 1400px;
}

Compiled CSS:

.new-row {
  display: flex;
  flex-wrap: wrap;
  margin-right: -15px;
  margin-left: -15px;
  max-width: 1200px;
}

.another-row {
  display: flex;
  flex-wrap: wrap;
  margin-right: -15px;
  margin-left: -15px;
  max-width: 1400px;
}

A mixin includes the properties everywhere it is included—making a copy each time—whereas an @extend groups the selectors and defines the properties once. You might think using a mixin creates unnessasary duplication, but again, you need to ask yourself “how easy will this be maintain if I use @extend?”

The difference in the compiled CSS has some important implications:

Load Order

With @extend the selectors will be grouped in the compiled CSS where the extended selector is defined. This can cause some unintended overrides.

Consider this example:

HTML:

<div class='row highlight-row'></div>

SCSS:

.red-text {
  color: red;
}

.row {
  color: green;
}

.highlight-row {
  @extend .red-text;
}

Compiled CSS:

.red-text,
.highlight-row {
  color: red;
}

.row {
  color: green;
}

So even though the Sass ordering makes it look like the row color would be red, the compiled CSS will make it green.

Groupings

@extend can result in difficult to read groups of selectors in the compiled CSS. You can end up with many classes all sharing the same declarations. Here is an example from a live Travel Tripper website:

In case it wasn’t immediately obvious, this is an example of what not to do.

Nesting

If you are using deeply nested Sass and you use @extend you will duplicate the fully nested selector for every @extend, resulting in bloated CSS:

.selector-1 .selector-2 .selector-3 .selector-4,
.selector-1 .selector-2 .selector-3 .selector-4 a,
.selector-1 .selector-2 .selector-3 .selector-4 li,
.selector-1 .selector-2 .selector-3 .selector-4 td {
  font-family: ariel;
}

Media Queries

@extend does not work inside media queries—media queries are not selectors.

Good Use Examples

There are only a couple good use cases for @extend. Here are two examples:

Buttons

Buttons tend to be an iffy use case for @extend. You could add common styles to .button and add color and font differences to .button-primary, for example, then add class="button button-primary" to your markup. Using @extend also works, and would only require a single class selector:

%button {
  padding: 10px 25px;
  font-family: "Font One", "Font Two";
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  background-color: #fff;
  border: 2px solid #fff;
}

.button-primary {
  @extend %button;
  color: $color-primary;
}

.button-secondary {
  @extend %button;
  color: $color-secondary;
}
Headers

A more useful example is probably headers. You might have two headers in your design files with the only difference being margin or font size.

.page-title {
  margin: 80px auto;
  padding-right: 15px;
  padding-left: 15px;
  font-family: $font-family-header;
  font-size: 43px;
  color: #fff;
  text-transform: uppercase;
  }

.display-title {
  @extend .page-title;
  margin-top: 0;
}

References

Offical Sass Guide: https://sass-lang.com/guide
Offical Sass Reference: http://sass-lang.com/documentation/file.SASS_REFERENCE.html

The Extend Concept: https://css-tricks.com/the-extend-concept/
What Nobody Told You About Sass @extend: https://www.sitepoint.com/sass-extend-nobody-told-you/
When to Use @extend; When to Use a Mixin: https://csswizardry.com/2014/11/when-to-use-extend-when-to-use-a-mixin/