Listen Up! Explain "CSS Specificity" to me RIGHT NOW, or the dog gets it!
This is the imaginary threat I anticipate coming from the back of the lab whenever I reach the CSS phase of my lecture (Don’t freak out. The dog photo isn’t real). This image came from a National Lampoon magazine cover published in 1973. Bear with me. I’m desperately trying to make a point.
Each time I teach this, I spend way too much time talking about specificity, and the students never get it. Well, they eventually get it, but they can’t hold it.
Remember this: It’s the priority rule. He who has the most attributes wins.
Maybe I should make a video about it. Nah. Too scary. Let’s write it out:
If you have two (or more) conflicting CSS rules that point to the same element, there are some basic rules that a browser follows to determine which one is most specific and therefore wins out.
It may not seem like something that important, and in most cases you won’t come across any conflicts at all, but the larger and more complex your CSS files become, or the more CSS files you start to juggle with, the greater likelihood there is of conflicts turning up.
If the selectors are the same then the latest one will always take precedence. For example, if you had:
p { color: red; }
p { color: blue; }
p elements would be colored blue because that rule came last.
However, you won’t usually have identical selectors with conflicting declarations on purpose (because there’s not much point). Conflicts quite legitimately come up, however, when you have nested selectors. In the following example:
div p { color: red; }
p { color: blue; }
It might seem that p elements within a div element would be colored blue, seeing as a rule to color p elements blue comes last, but they would actually be colored red due to the specificity of the first selector. Basically, the more specific a selector, the more preference it will be given when it comes to conflicting styles.
The actual specificity of a group of nested selectors takes some calculating. Basically, you give every id selector (“#something”) a value of 100, every class selector (“.something”) a value of 10 and every HTML selector (“something”) a value of 1. Then you add them all up and VIOLA!, you have the specificity value!
p
has a specificity of 1 (1 HTML selector)div p
has a specificity of 2 (2 HTML selectors; 1+1).tree
has a specificity of 10 (1 class selector)div p.tree
has a specificity of 12 (2 HTML selectors and a class selector; 1+1+10)#baobab
has a specificity of 100 (1 id selector)body #content .alternative p
has a specificity of 112 (HTML selector, id selector, class selector, HTML selector; 1+100+10+1)
So if all of these examples were used, div p.tree
(with a specificity of 12) would win out over div p
(with a specificity of 2) and body #content .alternative p
would win out over all of them, regardless of the order. Got it? No? Crap!
Why is this so confusing?!!
Web Design Guru Molly E. Holzschlag explains it this way: The confusion has to do with the specificity algorithm being different between CSS specifications. Since most standards-based designers and developers are working with CSS2.1 much of the time, I’m going to show how to calculate specificity according to the CSS2.1 specification. This way, you can make your calculations relevant to the kinds of selectors we’re using in contemporary CSS design.
Here’s an easy way to visualize specificity in CSS2.1:
Example | Presence of style in doc (inline style) | # of ID selectors | # of class selectors | # of Element (type) selectors |
---|---|---|---|---|
|
||||
p |
0, | 0, | 0, | 1 |
|
||||
p.warning |
0, | 0, | 1, | 1 |
|
||||
#content p.warning |
0, | 1, | 1, | 1 |
|
The final specificity calculations then would be:
p = 0, 0, 0, 1
p.warning = 0, 0, 1, 1
#content p.warning = 0, 1, 1, 1
Other items of specific interest:
- The universal selector has a specificity of
0, 0, 0, 0
- Inherited values have null specificity.
- According to the CSS2.1 specification, it can be interpreted that a pseudo element is calculated as an element, a pseudo-class is calculated as a class, and an attribute selector is also calculated as a class. Note that CSS2 says that pseudo elements should be ignored, further confusing the issue!
- As you can see in the above chart, if a rule is applied to an element with an inline style, the inline style has higher specificity than anything. So, you’d add a 1 to the beginning of the style in question, let’s say there’s an inline style on some instance of p , that particular selector would then have a specificity of 1, 0, 0, 1 , being the most specific rule of the bunch.
And, while it seems natural to drop the comma delimiters and count all this as if it were base 10 (which on first glance make sense) the specification clearly states that a “broad” base is necessary – potentially infinite. While it would be rare to have more than 10 individual selectors in a given category, base 10 doesn’t apply when there are more than 10 selectors present.
And now for something completely different..
Andy Clarke came up with a real cool visual explanation that should clear this up for all us Star Wars geeks. If you’re a Harry Potter fan, you’re sorta screwed here. Sorry.
We would love to hear your comments