Using @include vs @extend in Sass?

Sass

Sass Problem Overview


In Sass, I can't quite discern the difference between using @include with a mixin and using @extend with a placeholder class. Don't they amount to the same thing?

Sass Solutions


Solution 1 - Sass

Extends do not allow customization, but they produce very efficient CSS.

%button
  background-color: lightgrey
  &:hover, &:active
    background-color: white
  
a
  @extend %button
  
button
  @extend %button

Result:

a, button {
  background-color: lightgrey;
}
a:hover, button:hover, a:active, button:active {
  background-color: white;
}
  

With mixins, you get duplicated CSS, but you can use arguments to modify the result for each usage.

=button($main-color: lightgrey, $active-color: white)
  background-color: $main-color
  border: 1px solid black
  border-radius: 0.2em
  
  &:hover, &:active
    background-color: $active-color
  
a
  +button
  
button
  +button(pink, red)

Results in:

a {
  background-color: lightgrey;
  border: 1px solid black;
  border-radius: 0.2em;
}
a:hover, a:active {
  background-color: white;
}

button {
  background-color: pink;
  border: 1px solid black;
  border-radius: 0.2em;
}
button:hover, button:active {
  background-color: red;
}

Please follow this consecutive set of code examples to see how you can make your code cleaner and more maintainable by using extends and mixins effectively: http://thecodingdesigner.com/posts/balancing

Note that SASS unfortunately does not allow using extends inside media queries (and corresponding example from the above link is wrong). In the situation where you need to extend based on media queries, use a mixin:

=active
  display: block
  background-color: pink
  
%active
  +active
  
#main-menu
  @extend %active // Active by default
  
#secondary-menu
  @media (min-width: 20em)
    +active // Active only on wide screens

Result:

#main-menu {
  display: block;
  background-color: pink;
}

@media (min-width: 20em) {
  #secondary-menu {
    display: block;
    background-color: pink;
  }
}

Duplication is inevitable in this case, but you shouldn't care too much about it because web server's gzip compression will take care of it.

PS Note that you can declare placeholder classes within media queries.

Update 2014-12-28: Extends produce more compact CSS than mixins do, but this benefit is diminished when CSS is gzipped. If your server serves gzipped CSS (it really should!), then extends give you almost no benefit. So you can always use mixins! More on this here: http://www.sitepoint.com/sass-extend-nobody-told-you/

Solution 2 - Sass

A good approach is to use both - create a mixin that will allow you lots of customisation and then make extends for common configurations of that mixin. For example (SCSS Syntax):

@mixin my-button($size: 15, $color: red) {
  @include inline-block;
  @include border-radius(5px);
  font-size: $size + px;
  background-color: $color;
}
%button {
  @include my-button;
}
%alt-button {
  @include my-button(15, green);
}
%big-button {
  @include my-button(25);
}

This saves you from calling the my-button mixin over and over. It also means you don't have to remember the settings for common buttons but you still have the ability to make a super unique, one-off button should you choose.

I take this example from a blog post I wrote not long ago. Hope this helps.

Solution 3 - Sass

In my opinion extends are pure evil and should be avoided. Here is why:

given the scss:

%mystyle {color: blue;}
.mystyle-class {@extend %mystyle}
//basically anything not understood by target browser (such as :last-child in IE8):
::-webkit-input-placeholder {@extend %mystyle}

The following css will be generated:

.mystyle-class, ::-webkit-input-placeholder { //invalid in non-webkit browsers
  color: blue;
}

When a browser doesn’t understand a selector, it invalidates the entire line of selectors. This means that your precious mystyle-class is no longer blue (for many browsers). What does this really mean? If at any time you use an extend where a browser may not understand the selector every other use of the extend will be invalidated. This behavior also allows for evil nesting:

%mystyle {color: blue;}
@mixin mystyle-mixin {@extend %mystyle; height: 0;}
::-webkit-input-placeholder {@include mystyle-mixin} 
//you thought nesting in a mixin would make it safe?
.mystyle-class {@extend %mystyle;}

Result:

::-webkit-input-placeholder, .mystyle-class { //invalid in non-webkit browsers
  color: blue;
}

::-webkit-input-placeholder {
  height: 0;
}

Tl;dr: @extend is perfectly ok for as long as you never use it with any browser spesific selectors. If you do, it will suddenly tear down the styles wherever you have used it. Try to rely on mixins instead!

Solution 4 - Sass

Use mixins if it accepts a parameter, where the compiled output will change depending on what you pass into it.

@include opacity(0.1);

Use extend (with placeholder) for any static repeatable blocks of styles.

color: blue;
font-weight: bold;
font-size: 2em;

Solution 5 - Sass

I totally agree with the previous answer by d4nyll. There is a text about extend option and while I was researching this theme I found a lot of complaints about extend, so just have in mind that and if there is a possibility to use mixin instead of extend, just skip extend.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiontemporary_user_nameView Question on Stackoverflow
Solution 1 - SassAndrey Mikhaylov - lolmausView Answer on Stackoverflow
Solution 2 - SassFreddyBushBoyView Answer on Stackoverflow
Solution 3 - SassclearfixView Answer on Stackoverflow
Solution 4 - Sassd4nyllView Answer on Stackoverflow
Solution 5 - SassNesha ZoricView Answer on Stackoverflow