CSS Specificity Wars

This entry was published on October 7th 2005 and, incredibly, is still one of the most visited pages on my website, so twelve years later I decided to update it with a new graphic to print and pin near your monitor. If you find this useful, consider saying “thank you” with a small donation.

Join me, and together we can rule the galaxy as father and geeks! In 2005 I saw Aaron explain how the specificity of CSS selectors is calculated in a way which I hadn’t seen before. Then I came across a problem while building templates for a new project where two selectors behaved differently to how I expected and I realised that I had not completed my Jedi training.

The Dark Side

My problem was a simple one, how to serve a transparent PNG to browsers which support transparency and a GIF to browsers which didn’t at the time, without resorting to hacks, something that we did a lot back then. Here’s my markup:

<div id="nav-supp"> <p><a id="a-02" href="">Top</a></p> <!-- etc. --> </div>

My CSS starting point:

a#a-02 { background-image : url(n.gif); } a[id="a-02"] { background-image : url(n.png); }

I had assumed that a modern browser would see and apply both rules (with the second overriding the first) and that an older browser which does not understand attribute selectors would see and apply only the first, ignoring the second. I was wrong.

Modern browsers did not apply the PNG image as I expected. The reason? A standard ID selector wins over an attribute selector in terms of the cascade. Dagnammit! I know I should have read the specs, but somehow that particular pleasure had escaped me. If I had, I might have learned that:

ID selectors have a higher specificity than attribute selectors. For example, in HTML, the selector #p123 is more specific than [id=p123] in terms of the cascade.

Sith Lords

A little Googling uncovered some rather dry reading on the subject of selector specificity (resources below). First, let’s look back at what Lord Elasticus (Patrick Griffiths) wrote on the subject of specificity:

You give every id selector ("#whatever") a value of 100, every class selector (".whatever") a value of 10 and every HTML selector ("whatever") a value of 1. Then you add them all up and hey presto, you have the specificity value.

Darth Lemon quotes the W3C:

A selector’s specificity is calculated as follows:

count the number of ID attributes in the selector (= a )

) count the number of other attributes and pseudo-classes in the selector (= b )

) count the number of element names in the selector (= c )

) ignore pseudo-elements.

Concatenating the three numbers a - b - c (in a number system with a large base) gives the specificity.

Too much! For me, the W3C really is in a galaxy far, far away! Maths was never my strong point, so to help me understand calculating specificity better I made a chart based on the following specificity (or Sith power) values:

element selector

Specificity: 0,0,1 class selector

attribute selector

pseudo-class

Specificity: 0,1,0 (10) id selector

Specificity: 1,0,0 style attribute

Specificity: 1,0,0,0

Each character (selector) is given its own Sith power (specificity value) depending on how powerful they are in the ways of the Dark Side:

A storm trooper (element selector) is less powerful than Darth Maul (class selector*) Darth Maul is less powerful than Darth Vader (ID selector) Darth Vader is less powerful than the than the Emperor (style attribute) The Death Star blows up everything

* Attribute selectors and pseudo-classes have the same power as a class selector.

Here’s a CSS Specificity Wars graphic for you to download, print, and stick on your wall.

CSS Specificity Wars by Andy Clarke 2018.

Do not underestimate the power of the Dark Side

Amazingly, Star Wars helped me understand CSS better. Join me, and together we can rule the galaxy as father and geeks!

The 2005 version of this post was translated into:

Brazilian Portuguese by Mauricio

Dutch by Mark

Danish by Michael

Spanish by Ismael Celis.

Resources

Replies