Reprocessed, by Matt Patterson

Something approaching a weblog

#billy { don't be a: hero; }

The way that CSS's specificity (how browsers choose which CSS rules to apply) works can be a little baffling, even to old hands. I was writing rules for this site and ran into a problem where one style was overriding another where, I thought, it really shouldn't.

The problem was that I'd forgotten an important aspect of the way that selector specificity is worked out.

Consider these two selectors and a snippet of HTML:

div.special ul.extraSpecial li.reallySpecial a:link { color: blue; }
#billy a:link { color: red; }

<div id="billy" class="special">
    <ul class="extraSpecial">
        <li class="reallySpecial"><a href="test">List item</a></li>
    </ul>
</div>

Which one is going to match the <li> in that HTML?

Last week, I would've said the first rule. But I'd have been wrong. Oh so very wrong.

According to the spec, specificity is worked out by calculating 4 values and then concatenating them, which is enough like adding up to confuse. The 4 values are:

  1. Whether the rule is in a style attribute (i.e. inline) or not [1 or 0]
  2. How many ids there are in the selector (i.e. how many #billys there are) [add them up]
  3. How many class or attribute selectors there are (i.e. .special or [href="index.html"] [add them up]
  4. How many elements or pseudo-elements there are [add them up]

Note that there's nothing there about what order the various ids and classes and what have you are in, you just count 'em. Nice and simple.

So, if we go back to our first example and do the sums then we get the following results:

div.special ul.extraSpecial li.reallySpecial a:link { color: blue; } gives us:

  1. No style attributes here: 0
  2. No ids: 0
  3. Plenty of class selectors: 3
  4. Plenty of elements: 5

#billy a:link

  1. No style attributes here: 0
  2. We have an id: 1
  3. No class selectors: 0
  4. Two elements (:link counts too): 2

At first sight it looks like rule 1 scores 8 and rule 2, just 3. But we're not adding the totals, we're concatenating them, so rule 1 = 0035 = 35, but rule 2 = 0102 = 102, which is miles more specific...

In conclusion, watch where you put those ids...

Not forgetting:

This page is: