Sass Challenge: Use selector inheritance this week.
While the most talked about feature of Sass 3 has certainly been the new SCSS syntax, it is not the most interesting feature of that release. In fact, the goal of the new syntax was to remove a barrier to adoption so that more people could enjoy the powerful features that Sass has to offer. Without a doubt, the most powerful feature that Sass provides is selector inheritance.
Do you @extend
?
I don’t think people are really using @extend
yet. Maybe I’m wrong, but I don’t see people talking about it much yet and I don’t see code snippets using it very often. Why is this? I’m pretty sure it’s because we haven’t done a very good job explaining the feature. But also I think it’s because most of us haven’t tried to use it. Until we try it’s hard to know when and where to use a new concept. But I think when you get it, you’re going to wonder how you ever survived without it. And until you ask questions about it, we don’t know how to describe it better.
Why you should use inheritance
Inheritance makes an implicit relationship explicit. Like mathematical expressions or color transformations, it shows us, in our styles, that a relationship exists in the most concise way possible. Once you understand it, using inheritance will decrease the time it takes to write styles and understand them because the relationships are simple to understand and reason about. If you haven’t seen my refactoring of Digg’s stylesheets, please check it out because I think it’s a great example of inheritance.
Oh and it’s a really good way to reduce the size and increase the performance of your generated stylesheets.
The Challenge
This week, take a little time to read up on @extend
if you haven’t done so yet and then seek out an opportunity to use it. Get familiar with how it works and where it’s useful. Look at the output and make sure you understand it. If you do this, please post a link to the code in the comments so we can look at it. Maybe you’ll come up with a clever use we didn’t imagine or maybe you’ll commit a horrible sin without knowing it. We can all learn together.
The Basics
Here’s some basic documentation on the @extend
directive:
- The Feature Announcement that Natalie and I put together initially.
- Reference Documentation for a nuts and bolts description about how it works.
- Another Good Explaination by Thomas Reynolds
Some “Best Practices”
I use this term loosely because I think the best practices around selector inheritance are still forming. But here’s some conceptual guidelines you might find useful to help you decide when and where to use selector inheritance:
- Use
@extend
to replace complex mixins that do not accept any arguments. This will result in less output in the CSS as long as the contents of the class are longer than the extending selector. Remember that you can still define that base class in terms of mixins from libraries like compass. - Use
@extend
within a mixin to share base styles while still customizing the variable parts without breaking your existing API. - Use
@extend
to share implementation with a class has complex behavior that spans many selectors. - Use
@extend
to remove forced redundancy in your markup. Classes should be independent. If applying one class to an element assumes that some other class will also be applied, an implicit inheritance relationship exists – make it explicit and clean up your markup. - Use
@extend
within projects, less commonly in shared libraries between them – in those cases create a mixin to share and define a project-specific base class using it.
Some Interesting Uses
- Assuming you’ve got a reset in your stylesheet, you can extend basic elements. For instance,
div.code
could extendpre
. - Enforce a Style Guide without putting presentational classes into your markup.
- Go Object Oriented – the inspiration for the
@extend
directive. - Use a CSS framework without porting it. For instance Iain Hecker has done this with jQuery UI.
Some Gotchas
The Cascade
Because @extend
rewrites selectors, you may encounter issues with the cascade. Consider the following stylesheet:
.loud { font-weight: bold; }
.quiet { font-weight: lighter; }
.angry { @extend .loud; color: red; }
In conjunction with the following markup:
<div class="angry quiet">Can you hear me?</div>
Even though the .angry
class is declared after the .quiet
class in the source stylesheet, the .quiet class will win the font-weight property because when sass rewrites the selectors you get this:
.loud, .angry { font-weight: bold; }
.quiet { font-weight: lighter; }
.angry { color: red; }
This is certainly a case where a browser-based implementation would be able to do a better job. But in this case, at least, I believe it’s nonsensical to apply both of these classes to the same element. It’s our belief that selector rewriting is safe under normal use cases and that failures like this will generally be due to mixed concerns. Please let us know if you find a counter-example.
Multiple Stylesheets
The Sass compiler only operates on one CSS file at a time. Using @extend
in one sass stylesheet will not affect another sass stylesheet unless they are both imported into the same CSS file. This might be useful or it might be unexpected. If you’re building a single output file, then you’ll probably not notice this problem.
Overly Generic Classnames with Multiple Meanings
Consider a nested selector that extends a class that is similarly nested. If that class is an overly generic class name that is reused for a different purpose, you might end up rewriting more selectors than you intended. Example:
.clear { clear: both; }
#context {
.clear { background-color: transparent; }
#see-thru { @extend .clear; }
}
Becomes:
.clear, #context #see-thru {
clear: both;
}
#context .clear, #context #see-thru {
background-color: transparent;
}
Easy to catch in this situation, but with any reasonably complex stylesheet you can make this mistake if your classnames ever carry multiple meanings. Of course, this will cause problems in other ways so it’s best to only ever give a single meaning to each class name and only use nesting to apply customizations to that meaning in different contexts.
About Me
I am an open source hacker and stylesheet architect at LinkedIn. I live in San Jose, California with my wife and daughter.
Open Source
I'm the creator of Compass, a stylesheet authoring framework and I'm on the core team of Sass — the stylesheet syntax upon which Compass is built. I maintain about a dozen less well known ruby libraries and rails plugins on github, and am an active contributor of patches to the many open source projects that I use.