What's the difference and when to use @mixin and @extend in SASS?

2

Both @mixin and @extend seem to have the same goal:

  

Add a block of default code for a class.

But if they have this same purpose, what is the difference between them? And when should I use one or the other?

    
asked by anonymous 05.04.2016 / 16:25

1 answer

4

The use of @mixin and @extend may appear similar and have the same purpose, although true, they have different purposes as well as their pros and cons. Both, if used in the wrong way, can become a bad headache.

At first we may tend to use one or the other in the hills because of the practicality they give us to write SASS . With @mixin or @extend you can summarize numerous lines of code. But that's where the danger lies ..

Often what we write in SASS seems perfectly practical and perfect, everything seems in order, keeping the principle of DRY , but everything goes away when we look at our compiled code for CSS .

For example, the following code may look perfect on SASS :

@mixin placeHolder {
    display: -webkit-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}
.classe1 {
    @include placeholder;
}
.classe2 {
    @include placeholder;
}
.classe3 {
    @include placeholder;
}
.classe4 {
    @include placeholder;
}
.classe5 {
    @include placeholder;
}

But the CSS generated would be this:

.classe1 {
    display: -webkit-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}
.classe2 {
    display: -webkit-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}
.classe3 {
    display: -webkit-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}
.classe4 {
    display: -webkit-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}
.classe5 {
    display: -webkit-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}

The whole principle DRY , code maintenance and simplicity that in SASS seemed perfect, went by water ...

But that's where @extend comes to salvation! See the same logic with the use of @extend :

%placeHolder {
    display: -webkit-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}
.classe1 {
    @extend %placeHolder;
}
.classe2 {
    @extend %placeHolder;
}
.classe3 {
    @extend %placeHolder;
}
.classe4 {
    @extend %placeHolder;
}
.classe5 {
    @extend %placeHolder;
}

Generating the following code:

.classe1,
.classe2,
.classe3,
.classe4,
.classe5 {
    display: -webkit-box;
    display: -ms-flexbox;
    display: -webkit-flex;
    display: flex;
}

Perfect, now we can keep the code simple, clean, in a few lines of code.

MAS .....

Although this is true, it is a partial truth. The use of @extend when done abusively can break the whole basic principle of its use and generate many classes with few properties, making its final code extremely messy, with repetition of classes, going back to square one.

But what should I use? And when should I use?

A basic trick I like to remember is this:

  • Mixin: Use to generate your code dynamically through variables;
  • Extend: Use for common elements but there will be little repetition;

For example, suppose you have a button with the same style but with some color states. You could do this as follows:

@mixin corBotao($cor, $corHover) {
    border: 1px solid $cor;
    color: $cor;
    &:hover {
        background: $cor;
        color: $corHover;
    }
}
.button--azul {
    @include corBotao(blue, white);
    background: transparent;
    width: 64px;
    height: 48px;
    cursor: pointer;
    text-align: center;
}

In this way you will generate the following code:

.button--azul {
    background: transparent;
    width: 64px;
    height: 48px;
    cursor: pointer;
    text-align: center;
    /* Gerado pelo mixin */
    border: 1px solid blue;
    color: blue;
    &:hover {
        background: blue;
        color: white;
    }
}

With this you can generate several buttons with different colors without having to manually define which color each button will have.

To illustrate the use of @mixin , you can start from the same example above and improve our code. The properties of width , height , etc ... are common on all buttons, be it blue, red, green, etc ... Then just these properties we can convert to use @extend :

@mixin corBotao($cor, $corHover) {
    border: 1px solid $cor;
    color: $cor;
    &:hover {
        background: $cor;
        color: $corHover;
    }
}
%padraoBotao {
    background: transparent;
    width: 64px;
    height: 48px;
    cursor: pointer;
    text-align: center;
}

.button--azul {
    @include corBotao(blue, white);
    @extend %padraoBotao;
}
.button--verde {
    @include corBotao(green, white);
    @extend %padraoBotao;
}
.button--vermelho {
    @include corBotao(red, white);
    @extend %padraoBotao;
}

The above example will generate the following final code:

.button--azul,
.button--verde,
.button--vermelho {
    background: transparent;
    width: 64px;
    height: 48px;
    cursor: pointer;
    text-align: center;
}
.botao--azul {
    border: 1px solid blue;
    color: blue;
    &:hover {
        background: blue;
        color: white;
    }
}
.botao--verde {
    border: 1px solid green;
    color: green;
    &:hover {
        background: green;
        color: white;
    }
}
.botao--vermelho {
    border: 1px solid red;
    color: red;
    &:hover {
        background: red;
        color: white;
    }
}

See how the final code has stayed clean, organized, objective, and maintaining best practices.

What would not be recommended, would be to use the same extend for another element, even though it has the same characteristic.

Another example that I particularly use @mixin is for small codes that will be used in some classes, for example the use of display: flex; . Since we still need vendor-prefix , I do not want to write all of them by hand, but I also do not want to generate an unrelated grouping of classes, just by sharing the same display . For this I use a mixin, but it is a controlled use with a very specific purpose.

As seen in the examples, each has a very specific and intended use. Although they are similar DENTRO DO SASS , when we look at our CSS they have very distinct results that can worsen their final code rather than improve.

But despite all this difference, remember that it's not a rule to be followed (as I myself break it from time to time), it's all about planning and organizing your code.

For more good practice guides on CSS and SASS recommend see this project I'm working out in github , it is in constant development and I also accept contributions! In fact, they are more than welcome. More experiences generate best practices.

    
05.04.2016 / 16:27