css specificity
css is built around the struggle for dominance. The whole concept of css is constructed around cascading, better known to most people as the waterfall principle. While many people understand this principle, the exact details of the way css is applied in real life are usually a bit fuzzy. So no better time than the present to freshen up on css and the specificity of css selectors.
css specificity and exactness
css specificity is a misleading concept. If we look at the definition of specificity, the following is probably the most common interpretation:
The exactness with which a vocabulary term covers a concept.
Although it does cover the way css specificity is implemented, it is easy to misunderstand or misinterpret this definition. The "exactness" of css is a little different than you might expect at first glance.
css has more than one way to target a single html element. It can be done through ids, classes, pseudo-classes, the html elements themselves, through css selectors or even inline. All these ways carry a different weight of importance. So it makes a great difference whether you target a div through its class instead of its id. This weight is crucial when the "exactness" of a css rule if computed.
calculating specificity
Each selector carries a weight that represents its specificity. The sum of all these values is the computed weight for a selector, based on all elements within the selector. A little overview of the possible weights:
- 1,0,0,0 : inline styles
- 0,1,0,0 : ids
- 0,0,1,0 : classes, pseudo-classes and attributes
- 0,0,0,1 : elements and pseudo-elements
- 0,0,0,0 : the * (universal selector)
Completing this list are inherited properties and combinator, which carry no weight at all. This is different from the universal selector, which will still overwrite inherited properties.
It is possible that certain elements are targeted by more than one selector carrying the same weight. In this case, the selector appearing last in the source will take preference. An important rule which the whole concept of conditional comments is based on and which should be abused when dealing with IE6 faulty selector implementation.
9+1 is not 10
Something that got me confused at first is the fact that these calculations are not made in base-10. For example, you cannot get 11 classes to overwrite 1 id. Hence the representation of the values with "," which helps to clear up some possible confusion. All specificities are simply added within their respective weight category and the results is then compared to other selectors. A few simple examples:
h1 (weight: 0,0,0,1 ) * h1 (weight: 0,0,0,1 ) .class #id #id2 p (weight: 0,2,1,1 ) #id2 #id p .class (weight: 0,2,1,1 ) .class.class2>*~p (weight: 0,0,2,1 )
important addendum
h1 {color:#c0c0c0 !important;}
The !important declaration is a nasty little back door in the css specificity rules. By declaring something !important you fix that value as unchangeable. No other rules can change this property, no matter what their specificity is. Use this statement with caution, and don't abuse it when you are too lazy to find out which rule is holding your declaration back. !important should only be used within user style sheets or when delivering a piece of code that cannot be overruled by others. Apart from that, avoid it.
past articles revisited
In the end, css specificity is not all that difficult although it can be somewhat confusing. It plays a small role in the choice of class versus id as a targeted id can never be overruled by a string of classes in css. It plays another role in the ordering of css rules in combination with the nasty IE6 double class bug, as this bug has a huge effect on the specificity of a css rule (since classes are ignored and are not computed in the final value). Important things to consider when writing css.
I hope this brought some light in the darkness for some of you. It's all quite straight-forward but unless you're aware of all the details css specificity can be quite surprising.