Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

@extend and placeholders

@extend says: "this selector should get all the styles of that one". Unlike a mixin it does not copy declarations — it adds the selector to the existing rule. A placeholder selector starting with % is a rule made only for extending: it never appears in the CSS on its own.

A placeholder

Several kinds of messages share the same base styles. Put the base into a placeholder in styles/components/_alerts.scss:

// styles/components/_alerts.scss
%alert {
  padding: 12px 16px;
  border-radius: 8px;
}
 
.alert-success {
  @extend %alert;
  background: #dcfce7;
}
 
.alert-error {
  @extend %alert;
  background: #fee2e2;
}
// styles/main.scss
@use "components/alerts";
.alert-error, .alert-success {
  padding: 12px 16px;
  border-radius: 8px;
}
 
.alert-success {
  background: #dcfce7;
}
 
.alert-error {
  background: #fee2e2;
}
<style>
  .alert-error, .alert-success {
    padding: 12px 16px;
    border-radius: 8px;
  }
 
  .alert-success {
    background: #dcfce7;
  }
 
  .alert-error {
    background: #fee2e2;
  }
</style>
 
<p class="alert-success">The order is placed.</p>
<p class="alert-error">The card was declined.</p>

Both selectors were added to one rule: the base declarations exist in the CSS only once. %alert itself is not in the output.

Extending a class

You can extend an ordinary class too:

// styles/main.scss
.btn {
  padding: 8px 16px;
}
 
.btn-large {
  @extend .btn;
  font-size: 20px;
}
.btn, .btn-large {
  padding: 8px 16px;
}
 
.btn-large {
  font-size: 20px;
}

Now in the HTML class="btn-large" is enough — there is no need to write class="btn btn-large".

Why to be careful

@extend changes every rule where the extended selector appears, not only the first one. If .btn is also used in some other rule, .btn-large gets added there too:

// styles/main.scss
.btn {
  padding: 8px 16px;
}
 
.header .btn {
  color: white;
}
 
.btn-large {
  @extend .btn;
}
.btn, .btn-large {
  padding: 8px 16px;
}
 
.header .btn, .header .btn-large {
  color: white;
}

In a big project such selectors multiply, the CSS becomes hard to read, and the order of rules can change which style wins. Rules of thumb:

SituationUse
Shared base styles inside one component file@extend of a %placeholder
Reusable styles with parametersA mixin
Styles that should combine in the HTMLTwo classes: btn btn-large

Extend only placeholders, not real classes, and keep the placeholder in the same file as the rules that extend it.

Common mistake

@extend cannot reach out of a media query to a selector defined outside it:

// styles/main.scss
%hidden {
  display: none;
}
 
@media (max-width: 600px) {
  .sidebar {
    @extend %hidden;
  }
}

Sass stops with the error You may not @extend selectors across media queries. In this case use a mixin: it copies the declarations into the media query, and that always works.

Thanks for reading!

Donate to the site — we work hard for you.