HTML & CSS
Article

The Benefits of Inheritance via @extend in Sass

By David Nguyen

Organizing CSS stylesheets has become crucial to styling large scale websites effectively, but stylesheets in our projects have been getting larger, more complex and harder to maintain as they develop. This is where Sass comes in to make everything simpler.

For those who have yet to explore Sass, it is an extension of CSS. It provides features for us that do not exist in native CSS such as expressions, variables, nesting, mixins (Sass’ name for functions), inheritance, and more.

In this article I’m going to give an overview of inheritance in Sass using @extend. I’ll cover the advantages this feature brings and my experiences when using it in my own projects. It is important to note that @extend can be misused, Hugo Giraudel here at SitePoint even wrote a piece on Why You Should Avoid Sass @extend. So be aware that @extend can be a contentious subject.

In the following examples, I will use the SCSS syntax. This is the syntax which contains all the features and structure of CSS, with Sass’ additional features.

What is @extend?

@extend is a feature of Sass that allows classes to share a set of properties with one another. Selectors that @extend a class in Sass will have their selector included right up next to the class it is extending, resulting in a comma separated list.

Its syntax looks like so:

@extend .class-name;

Usage

Using @extend looks like so:

.foo {
  color: black;
  border: 1px solid black;
}

.bar {
  @extend .foo;
  background-color: red;
}

This is compiled to:

.foo, .bar {
  color: black;
  border: 1px solid black;
}

.bar {
  background-color: red;
}

In the example above, I defined .foo and .bar which have the following features:

  • .bar inherits from .foo, containing all properties of parent class .foo.
  • .bar extends .foo by adding the property background-color.

Knowing the basics, we will now look at some use cases for @extend.

Using @extend

Use Case 1: Duplication

Duplication of properties between classes is hard to avoid when putting together CSS. This can make your stylesheets more complicated. For example:

.breakfast {
  color: #333;
  border: 1px solid #bbb;
  box-shadow: 1px 1px 0 #ddd;
  margin: 0 0 10px;
  padding: 15px;
}

.lunch {
  background-color: yellow;
  color: #333;
  border: 1px solid #bbb;
  box-shadow: 1px 1px 0 #ddd;
  margin: 0 0 10px;
  padding: 15px;
}

.dinner {
  background-color: orange;
  color: #333;
  border: 1px solid #bbb;
  box-shadow: 1px 1px 0 #ddd;
  margin: 0 0 10px;
  padding: 15px;
}

As we can see in the example above, .breakfast, .lunch and .dinner contain the properties color, border, box-shadow, margin and padding with the same values. These properties are duplicated, making our code look messy, so let’s rewrite it with @extend:

.meal-box {
  color: #333;
  border: 1px solid #bbb;
  box-shadow: 1px 1px 0 #ddd;
  margin: 0 0 10px;
  padding: 15px;
}

.breakfast {
  @extend .meal-box;
}

.lunch {
  @extend .meal-box;
  background-color: yellow;
}

.dinner {
  @extend .meal-box;
  background-color: orange;
}

In the rewritten CSS above, we can see that using Sass helps our markup become cleaner than CSS alone.

See the Pen Duplication of Properties in SCSS by SitePoint (@SitePoint) on CodePen.

Case 2: Moving Multiple Classes out of HTML

There are often cases when designing a page when one class should have all the styles of another class. We often handle this case by using multiple class names in the HTML.

Our CSS would look like so:

.candy {
  background-color: black;
  border: 1px solid red;
  box-shadow: 1px 1px 0 #ddd;
  padding: 15px;
}

.strawberry-candy {
  background-color: #ff6666;
  color: white;
}

Our HTML for that CSS:

<div class="candy strawberry-candy">
  This is the strawberry candy!
</div>

In the example above, we have two classes in our <div>. Imagine how messy this would be if we had several classes:

<div class="candy strawberry-candy sugar-free-candy free-candy">
  This is just an example
</div>

The HTML code above could become quite complex. Some web developers prefer it this way, however I prefer inheritance in my Sass styles:

.candy {
  background-color: black;
  border: 1px solid red;
  box-shadow: 1px 1px 0 #ddd;
  padding: 15px;
}

.strawberry-candy {
  @extend .candy;
  background-color: #ff6666;
  color: white;
}

With our HTML now looking like so:

<div class="strawberry-candy">
  This is the very sweet candy!
</div>

This time we only need one class. All styles defined for class .candy are also applied to class .strawberry-candy, now our HTML code becomes cleaner.

See the Pen Moving Multiple Classes out of HTML with @extend by SitePoint (@SitePoint) on CodePen.

Case 3: Extending complex selectors

Class selectors are not the only things that can be extended. We can also extend complex selectors into a single element, such as a:hover, .parentClass.childClass and so on. For example:

.example {
  color: black;
}

.example:hover {
  color: red;
}

.hover-link {
  @extend .example:hover;
}

This is compiled to:

.example {
  color: black;
}

.example:hover, .hover-link {
  color: red;
}

Which we can then use in our HTML like this:

<p>This is an example sentence with <a class="example">a sample link</a>
that should have a typical hover style.</p>
<p>This is another sentence, this time with 
<a class="hover-link">an eternally hovered link</a>.</p>

See the Pen Extending complex selectors with @extend by SitePoint (@SitePoint) on CodePen.

Advantages of @extend

Walking through the examples above, we can see several advantages of inheritance via @extend. These include:

Cleaner HTML Classes

As you can see in the second case study, using so many classes in one element may make it hard to determine the root cause if you run into issues. The structure of HTML tags also does not look very nice and clean.

From my point of view when making a good product, we consider not only the perspective of end-user but also the quality of our development strategy. Therefore, @extend helps us structure our classes in a cleaner way within each HTML element.

Reducing Duplication of CSS

In web development, we always have some duplication within our CSS styles. Hence, reusing written CSS source code can be extremely necessary. @extend can help us reuse our CSS when it is appropriate and cleaner to do so.

Saving time and effort

With the two aforementioned advantages, developers can save time and effort whilst developing.

Developers can reuse CSS for various elements, reducing the effort needed to find the root cause of CSS issues and making their CSS structure nice and clean.

However, using @extend is not without its dangers. The above advantages only apply when @extend is used carefully — it can be overused causing the opposite effect.

The Dangers of @extend

I have applied @extend in my own projects and I need to provide a word of caution when using @extend. You have to be careful.

@extend can increase your CSS file size drastically and impact the performance of your CSS when used without care. I had my share of pain in a situation just like this and spent lots of time refactoring my Sass’ use of @extend. Here is an example of how I initially used @extend incorrectly:

Example:

.base-css {
   color: red;
   font-size: 15px;
   font-weight: bold;
 }

 .btn {
   @extend .base-css;
   padding: 5px;
 }

 .warning-message {
   @extend .base-css;
   background-color: red;
 }

 .footer {
   @extend .base-css;
   color: #fff;
 }

 .content {
   @extend .base-css;
   margin: 10px;
 }

is compiled to:

.base-css, .btn, .warning-message, .footer, .content {
  color: red;
  font-size: 15px;
  font-weight: bold;
}

.btn {
  padding: 5px;
}

.warning-message {
  background-color: red;
}

.footer {
  color: #fff;
}

.content {
  margin: 10px;
}

In this example, .base-css is a class with many inherited classes based on it. If you take a look at the example, you can see that the inherited classes are not related to each other. I have .btn for my buttons and .footer for my footer. If I have 100 classes inheriting from .base-css, the selectors which have .base-css characteristics will increase. This significantly and unnecessarily complicates our CSS end result. Moreover, this makes it more difficult to check the properties of each selector.

After re-factoring my Sass, I realised that we should only use @extend when the inherited class directly relates to the object we are inheriting from. It should be a variation of the object or style, rather than a blanket rule for many unrelated elements. For inheritance like my example above, we should rely on CSS’ existing capabilities to cascade our styles into child elements.

.btn {
  color: #fff;
  font-size: 15px;
  font-weight: bold;
}

.btn-success {
  @extend .btn;
  background-color: green;
}

.btn-warning {
  @extend .btn;
  background-color: orange;
}

.btn-info {
  @extend .btn;
  background-color: blue;
}

.btn-error {
  @extend .btn;
  background-color: red;
}

is compiled to:

.btn, .btn-success, .btn-warning, .btn-info, .btn-error {
  color: #fff;
  font-size: 15px;
  font-weight: bold:
}
.btn-success {
  background-color: green;
}

.btn-warning {
  background-color: orange;
}

.btn-info {
  background-color: blue;
}

.btn-error {
  background-color: red;
}

We can see that the above example is much more correct and reasonable. We have reduced the scope by applying @extend only to classes that should inherit from one another due to being a variation of a type of object. For example, the above styles are all related to differing types of buttons.

Conclusion

Sass is a valuable extension that can improve our CSS to make it cleaner, well-structured, organized and easy to develop and maintain. If you have not tried Sass before, I highly recommend it. When you feel more comfortable with the basics of Sass, we recommend reading Hugo Giraudel’s SitePoint article on What Nobody Told You About Sass’s @extend. We also have an entire Sass reference guide at SitePoint’s Sass Reference with plenty of examples for you to explore.

Thank you to Steve and Ezekiel in the comments for picking up an error in the first version of this post, it has since been updated.

  • markbrown4

    The biggest problem I find with @extend is that it becomes impossible to know what you’re changing. To add a new rule to .btn {} safely you first need to search the codebase for .btn to see if it’s been extended elsewhere to see if the new rule is going to leak elsewhere and have unintended effects. I’m sure there’s cases where it’s a good option but I’ve found it so problematic that I avoid it entirely.

    • William H

      Placeholders

      %btn { … }
      .btn { @extend %btn }
      .btn-info { @extend %btn }

      • markbrown4

        Thanks! I didn’t know placeholders were a thing. They would certainly help you be aware that the properties are special and to be careful.

  • Steve Tweeddale

    Err, basically everything in the opening “What is @extend?” section is wrong. The given scss doesn’t compile the css shown. Nor is the @extend mechanism at all to do with copying/overriding properties. It’s about selectors.

    • Ezekiel Gabrielse

      I was about to reply with the same thing. The initial example is very misleading. Rather than showing that extend acts as a mixin (like you’ve put forth), you should make it clear that the selector that extends will actually get _hoisted_ up to where the extended selector is. This will result in a comma separated list, rather than the duplicated properties in the example. That makes all the difference in the world due to CSS’ cascading nature.

      • Patrick Catanzariti

        To both Steve and Ezekiel – thank you both so much for picking this up! As editor, I can’t believe I missed this… I’ve updated the initial example and explanation to be more accurate. Once again, a very big thank you for calling this to my attention!

        I’ve mentioned you both in a thank you at the end of the post :)

  • Dwåne Røbertsen

    Nice article but you’re kind of promoting bad practice in my opinion. You should avoid extending classes and only extend -%placeholders. Your just adding more (unused) classes to your css output. eg The .meal-box class. Futhermore, the real danger with extending classes is that you get all the related rules with it as well which most of the time is an unwanted side effect. Making your code anything but DRY and defeating the whole purpose of inheritance. My two cents, @extend is great! But only when used with %placeholders.

  • Vivian

    I love placeholders and extend but we can’t use @extend in media queries. Since I began to write code with mobile first approach that’s the biggest problem imo. Sad :(

  • squeakz

    The way @extend is used above is not that useful. I think this use-case would be better served by adding multiple classes to elements. No scss needed.

  • squeakz

    The way @extend is used above is not that useful. I think this use-case would be better served by adding multiple classes to elements. No scss needed.

  • https://nadandosobrelasolas.blogspot.com Daniel Lanza

    Thank you!! That’s what I was looking for.
    I will implemented this tip for Bootstrap classes. This way I cannot be worried about updating all my post when upgrading Bootstrap version, since a new version can change its classes names.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Front-end, once a week, for free.