7

A common problem I have with @extend is when trying to override the inherited properties with another @extend.

Here's an example:

// class selectors to be @extended
// these could also use % to be silent/placeholder selectors
.size-2xl {
    @include rem(font-size, 40px);
}
.size-3xl {
    @include rem(font-size, 60px);
}

// mapping the class selector properties onto some structural classes
.heading1 {
    @extend .size-3xl;
}
.heading1-small {
    @extend .heading1;
    @extend .size-2xl;
}

When the SCSS is compiled, .heading1 and .heading1-small will get the correct properties, but .heading1-small will appear too large.

This seems to occur when the @extend-able class is mapped onto a few different selectors.

When the SCSS is compiled to CSS, the various selectors are combined into one or more rule sets with multiple selectors.

Sometimes the SCSS appears to be compiled 'out of order', so that the compiled .heading1 multiple selector is output after the .heading1-small multiple selector.

It could even be the nested @extend causing this behaviour.

What is the best way to avoid this situation? Some things I can think of off the top of my head are:

  1. use @include('size-2xl') (less DRY)
  2. don't @extend rules containing @extend (limits the use of @extend)

Thanks.

Dan
  • 423
  • 4
  • 9

1 Answers1

17

The rulesets in the output CSS are in the exact same place/order/sequence as they have been defined in SCSS, just that you only output the extended .size-2xl and .size-3xl rulesets. So you need to switch the places of this two rule definitions (see demo) or define the size rules as mixins and include them in the header rules (see demo). So, I think you must be confusing something about how @extend works.

If you have something like that:

.class1 {
   foo: bar1;
}

.class2 {
   foo: bar2;
   @extend .class1;
}

You will only add the selector .class2 to the already existing ruleset with the selector .class1 - so the output will look like this:

.class1, .class2 {
   foo: bar1;
}

.class2 {
   foo: bar2;
}

However, if we do not add any new properties to .class2 but just use @extend:

.class1 {
   foo: bar1;
}

.class2 {
   @extend .class1;
}

The .class2 ruleset will not be printed to CSS and only the selector will be added to .class1 - hence the output:

.class1, .class2 {
   foo: bar1;
}

This is more or less what you are doing, just adding the selectors .header1 and .header2 to the rules .size-2xl and .size-3xl, so the output will be in the same place/order in which these rules are defined in SCSS.

So what you get at the end in your example:

  • you define the rulesets .size-2xl and .size-3xl
  • you add the .header1-small selector to the rulesets .size-2xl
  • you add the .header1-small to the .header1 selector and add both to ruleset .size-3xl
  • ruleset .size-2xl (now after extending: .size-2xl, .header1-small) gets printed to CSS
  • ruleset .size-3xl (now after extending: .size-3xl, .header1, .header1-small) gets printed to CSS
  • ruleset .header1 (also the extended one .header1, .header1-small) doesn't get printed out as it does not have any defined properties
  • ruleset .header1-small doesn't get printed out as it does not have any defined properties

Another note: The same will happen also if you use placeholder selectors (%) just that then it may be even more confusing, for example in .size-3xl, .header1, .header1-small the .size-3xl will be invisible, but in the CSS the whole thing will still get compiled in the place where the .size-3xl rule was defined in SCSS.

Community
  • 1
  • 1
Martin Turjak
  • 20,896
  • 5
  • 56
  • 76
  • Thanks, that's a really good answer. Now I understand how the extended selectors are built, I can see why the `.size-3xl` rule overrides the `.size-2xl` rule, and that `%` placeholder selectors aren't a solution to this. It seems that `@extend` needs to be used very carefully, and avoided when variations are expected (as it is problematic to 'override'). I have read the SMACSS and SMURF literature and the latter only uses `@extend` within modules. It seems that may be a better way forward. Do you yourself limit your use of `@extend` to the SMURF approach? – Dan Oct 24 '13 at 21:58
  • 3
    +1 Very illustrative examples. I always struggled to understand the ways of `@extend` exactly. Cheers mate! – BobbyZ Oct 27 '13 at 14:34