CSS | The Cascade: Specificity

Note: Should you need it, there is a mini glossary at the end of this article.

Specificity is a wonderfully powerful, wildly frustrating and weirdly mystical mechanism in the CSS-sphere. With simpler applications and pages that have few elements in the markup, declaring styling can be relatively straight forward. But as the number of elements, classes and ids begins to grow, when you begin including stylistic libraries (or maybe even start working with Sass and its & syntax), specificity can begin to get slightly confusing.

For starters, specificity is applied to a ruleset through a selector. There is a wide range of selectors, which I’ll dive into more deeply another time, but for now we’ll be referring to three of them as we use them in CSS—namely an element (e.g. <div></div> ), a .some-class (defined in markup a class="some-class") and #some-id (defined in markup as id="some-id").

Specificity is frequently explained as a point system, where an element is worth 1, a .class worth 10, an #id worth 100*.

According to that point system, the weight of specificity is placed on selectors based on an ascending value:

Up to here, all well and good. This is a really useful way of understanding how specificity gets determined by your selectors. The higher the total of the selector combinations, the more specific your ruleset and that is how particular styling gets chosen over others. Theoretically, you could link together as many selectors as you can be bothered to type out (as long as they exist in your markup), in order to be precise about the styling you want to apply to a particular element, and to be certain that that is the style that will be applied.

But! This logic implies that if you have enough elements in a selector, that selector will trump the specificity of a selector that is just a single .class.

Let’s assume we have 11 nested <div></div>s in our markup, and we decided (for the sake of curiosity because I can’t think of a real life application of this) write the following CSS.

div div div div div div div div div div div div {
height: 100px;
width: 100px;
background: thistle;
}

This will certainly apply those styles to that last div. But what if our last div had a class called .special-class, and our CSS file looked like this:

.special-class {
background: rebeccapurple;
}
div div div div div div div div div div div div {
height: 100px;
width: 100px;
background: thistle;
}

You’ve got 11 divs there, so if each div is worth 1 and .special-class is worth 10. According to the math in the table above, you would expect the specificity of the 11 divs to be greater than the single .special-class .

But, it isn’t.

Such suspicious

Run this code pen and see for yourself!

It turns out that specificity is determined by those points being concatenated. Basically, the total values are strung up sequentially, they aren’t added up. So if we drew our point-system-table differently, the running total would look more like this:

So when we create a selector with 11 divs , our total specificity points are going to be [0,0,11]. And a single class is [0,10,0], which is still more than that (because of its position in the scorecard, if you will).

Concatenation used to have a sort of memory limit. When that was reached, it would ‘spill over’ and surpass the specificity of the technically more valuable selector. But that was at the point where the specificity points rose above 255, so our scorecard of an element-only selector would have to look like [0,0,256] for it to be greater than [0,1,0]. Currently, this still seems to be the case for the Firefox and Internet Explorer rendering engines, but that memory limit is significantly higher with Chrome, Safari and Opera.

Nonetheless, as more styles and components start popping up on your page, and your selectors start looking far less simple than the examples above, it’s quite helpful to understand what the specificity specifics (ha) are, and how they play into the cascade.

Go forth and style! 💪

*In this explanation, we’ve excluded inline styles and !important, which have higher specificity. An inline style <div style="background: hotpink"></div> is generally valued at ‘1000’, but a declaration with the !important attribute can be used to trump that. However, the ultimate override is an !important inside an inline style, but that’s a bad idea. Let’s not ever do that. Let’s try and avoid !important in general. I’ve talked about importance, too, if you want to know more. Back up .


^ Glossary (sort of):

declaration

property: value

declaration block
{
property: value;
property: value;
}
ruleset
selector {
property: value;
property: value;
}