CSS and #noparents
#noparents is more than an emotionally charged hashtag to express your individuality and independence as an angsty teenager. Turns out it makes a lot of sense when writing CSS, too.
The fuck?
Consider the following snippets of HTML and CSS:
<div class="jumbotron">
<h1 class="text-danger">Heading</h1>
</div>
.jumbotron h1 {
color: #333;
}
.text-danger {
color: #f00;
}
To summarize, we have a .jumbotron h1
that should have red text with the .text-danger
utility class. The problem is, due to the specificity (a parent class preceding an open-ended tag) of the first rule, our utility class has no effect. The text will remain dark gray. Shit.
Classes to the rescue
If we modify our approach, we nullify the problem and walk away with some additional benefits.
<div class="jumbotron">
<h1 class="jumbotron-heading text-danger">Heading</h1>
</div>
.jumbotron-heading {
color: #333;
}
.text-danger {
color: #f00;
}
Now, adding the .text-danger
class will work as intended. It’s worth noting two things here:
- No matter what, this relies on CSS being in the proper order, but that’s always true and out of our control.
- Alternate solutions could include using
!important
or writing overrides to these kind of specific collisions. Both options suck.
Bottom line: removing the parent and using a single class as our selector is the best option, and it pays off.
Dem benefits
So, we wrote more HTML to avoid writing even more CSS. How’s this a win and why does it matter?
- To start, we’ve decreased the specificity of our selector. Now, any single class appearing later in our code can take over with ease, just as it does in our updated example. This is how CSS works, and keeping your code to that standard keeps your sanity.
- In selectors, classes perform better than elements. Removing that
h1
from our CSS rule for the heading helps the browser render the page faster. In many cases this isn’t that helpful, but for larger project (like maybe a CSS framework or web app?) it can make a world of difference. - A series of classes for each component promotes more flexible and durable design systems. The use of
.jumbotron
and.jumbotron-heading
logically groups code, more effectively scopes CSS, and promotes a consistent naming convention.
I’d say those are some solid wins, especially when applied across an entire project.
Applying it
I’ll be the first to say Bootstrap doesn’t do this enough, and it’s to our detriment. Whenever we start work on v4, I’ll be testing this approach. There will inevitably be situations where we need to keep the parents to prevent collisions out of our control (e.g., nav components and dropdowns), but I imagine we can still improve that. We’ll get there in time as we continue to experiment.
Until then kids, remember this: when it comes to CSS specificity, it’s #noparents.