421

I have this in my SCSS file:

.class-a{
  display: inline-block;
  //some other properties
  &:hover{
   color: darken(#FFFFFF, 10%);
 }  
}

.class-b{

 //Inherite class-a here

 //some properties
}

In class-b, I would like to inherite all properties and nested declarations of class-a. How is this done? I tried using @include class-a, but that just throws an error when compiling.

Lorenzo Polidori
  • 10,332
  • 10
  • 51
  • 60
F21
  • 32,163
  • 26
  • 99
  • 170

6 Answers6

821

Looks like @mixin and @include are not needed for a simple case like this.

One can just do:

.myclass {
  font-weight: bold;
  font-size: 90px;
}

.myotherclass {
  @extend .myclass;
  color: #000000;
}
jeerbl
  • 7,537
  • 5
  • 25
  • 39
F21
  • 32,163
  • 26
  • 99
  • 170
  • 53
    @extend works fine, but won't work if either of the classes is within a directive (usually a media query); unless they are both in the same directive. – MartinAnsty May 29 '13 at 14:37
  • 22
    see here for some fun facts about `@extend` - there's some tricky side effects you should be aware of: http://stackoverflow.com/questions/30744625/sass-and-bootstrap-mixins-vs-extends/30744854#30744854 – Toni Leigh Sep 23 '15 at 07:53
  • 2
    Thank you @ToniLeigh, PlaceHolder's are interesting as they save off generation of **an additional CSS selector** if the parent selector is only used to extend(not used anywhere). Like in the example above `.myclass` is not used anywhere else(I suppose) apart from `.myotherclass`, then it's better to have `.myclass` defined as `%myclass` and extended in `.myotherclass` as `@extend %myclass;`. It will generate as `.myotherclass{ font-weight: bold; font-size: 90px; color: #000000; }` – Abhijeet Jan 18 '16 at 06:18
  • 5
    [Example of using Place Holder](http://www.sassmeister.com/gist/39c0dfd87cfb1fce2b8b) Vs [Example of using normal class selector](http://www.sassmeister.com/gist/949aa56de85e5eca03de) – Abhijeet Jan 18 '16 at 06:26
  • @MartinAnsty Well, that sucks. – Abram Jun 08 '19 at 19:24
  • @MartinAnsty, [this answer](https://stackoverflow.com/questions/9560170#66259322) makes that possible by wrapping the extend inside a mixin. – Eagle_ Jun 13 '22 at 15:34
75

Try this:

  1. Create a placeholder base class (%base-class) with the common properties
  2. Extend your class (.my-base-class) with this placeholder.
  3. Now you can extend %base-class in any of your classes (e.g. .my-class).

    %base-class {
       width: 80%;
       margin-left: 10%;
       margin-right: 10%;
    }
    
    .my-base-class {
        @extend %base-class;
    }
    
    .my-class {
        @extend %base-class;
        margin-bottom: 40px;
    }
    
Mirodinho
  • 1,171
  • 1
  • 13
  • 25
Ashwin
  • 7,277
  • 1
  • 48
  • 70
  • 1
    @Yevgeniy Afanasyev No, you don't extend a class directly, but you can directly extend a placeholder. – Ashwin Oct 24 '18 at 06:55
  • 1
    @Yevgeniy Afanasyev extending the class directly (most popular answer) did not work for me, but extending a placeholder did the work. Hence I posted the answer since it is not the same answer. – Ashwin Oct 24 '18 at 07:19
  • 3
    Thank you for posting an alternative answer, but it is not clear from your answer why do we need it. If you please can add more reasoning to clarify a use case or advantages of this approach, it would be appreciated. Thank you. – Yevgeniy Afanasyev Oct 24 '18 at 21:36
32

This will include all rules from .someclass in .myclass

.myclass {
    @extend .someclass;
}
Mladen Janjetovic
  • 13,844
  • 8
  • 72
  • 82
mcmaxwell
  • 477
  • 4
  • 3
  • 42
    While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value. – adiga Jan 03 '18 at 12:24
  • 5
    ```@extend #{'.my-class', '.my-other-class'};``` – iarroyo Jan 25 '18 at 14:22
  • 5
    What's the meaning of the hashbang here? – Konrad Viltersten Dec 20 '19 at 15:45
  • @KonradViltersten that's not a hashbang. It's just a hash mark. Just F andbody's I. – dev_willis Feb 02 '21 at 18:55
  • 4
    @dev_willis Hmmm... I don't understand *just F andbody's I*. Is it a play on words or am I just slow today? – Konrad Viltersten Feb 03 '21 at 17:56
  • @KonradViltersten sorry, yeah; it's just a play on words. For Anybody's Information, instead of specifically _Your_ Information. – dev_willis Feb 04 '21 at 16:57
  • @dev_willis Ah, hahaha - like *FYI* but instead *F-**anybody's**-I*. Nope, mate. That was too sophisticated for my pretty head. :) – Konrad Viltersten Feb 04 '21 at 19:19
  • 1
    @dev_willis However, that doesn't answer the question in comment. What's the maning of the hashbang (or, as you FAI'ed, hash mark, hashtag, or sharp, square, fence etc.)? – Konrad Viltersten Feb 04 '21 at 19:22
  • @KonradViltersten yeah, I don't really have a good answer for that. Normally, #{} is used for interpolation but in this situation all it will do is remove the quotes from those strings. So `@extend #{'.my-class', '.my-other-class'};` produces the same result as simply `@extend .my-class, .my-other-class;`, as far as I can tell. I'm still transitioning to SASS from LESS so perhaps there's something more advanced going on here that I don't understand but it looks pretty pointless to me. – dev_willis Feb 05 '21 at 15:23
  • This is why I prefer LESS over SASS. Why it can't just be .classB{.classA; ....} – Mladen Janjetovic Aug 16 '22 at 13:12
18

Using @extend is a fine solution, but be aware that the compiled css will break up the class definition. Any classes that extends the same placeholder will be grouped together and the rules that aren't extended in the class will be in a separate definition. If several classes become extended, it can become unruly to look up a selector in the compiled css or the dev tools. Whereas a mixin will duplicate the mixin code and add any additional styles.

You can see the difference between @extend and @mixin in this sassmeister

Ari
  • 1,595
  • 12
  • 20
8

Another option could be using an Attribute Selector:

[class^="your-class-name"]{
  //your style here
}

Whereas every class starting with "your-class-name" uses this style.

So in your case, you could do it like so:

[class^="class"]{
  display: inline-block;
  //some other properties
  &:hover{
   color: darken(#FFFFFF, 10%);
 }  
}

.class-b{
  //specifically for class b
  width: 100px;
  &:hover{
     color: darken(#FFFFFF, 20%);
  }
}

More about Attribute Selectors on w3Schools

Khanji
  • 158
  • 1
  • 8
1

Combine Mixin with Extend

I just stumbled upon a combination of Mixin and Extend:

reused blocks:

.block1 { box-shadow: 0 5px 10px #000; }

.block2 { box-shadow: 5px 0 10px #000; }

.block3 { box-shadow: 0 0 1px #000; }

dynamic mixin:

@mixin customExtend($class){ @extend .#{$class}; }

use mixin:

like: @include customExtend(block1);

h1 {color: fff; @include customExtend(block2);}

Sass will compile only the mixins content to the extended blocks, which makes it able to combine blocks without generating duplicate code. The Extend logic only puts the classname of the Mixin import location in the block1, ..., ... {box-shadow: 0 5px 10px #000;}

Eagle_
  • 449
  • 1
  • 4
  • 12
  • 2
    How does it differ from just `@extend` (in `h1`)? Please show the output CSS in each case. – ADTC Oct 07 '22 at 08:19
  • For me it generates the same code as direct `@extend`, and it suffers from the same [problem of generating too much selectors](https://stackoverflow.com/questions/25557939/why-is-sass-producing-so-many-css-rules)... – Nickolay Aug 28 '23 at 09:54