One thing always puzzled me when working with CSS style sheets - how do browsers interpret conflicting attributes?
Certainly the order in which attributes appear in the CSS files and the selectors used play an important role - but isn't there anything more to it?
It seems there is - and on complex projects with large CSS files one can run into problems very easily.
Consider the following example,
<html> <head> <style> div { border: 1px solid #999999; } body .box2 div { background: green; } div.box3 { background: blue; } </style> </head> <body> <div class="box1">Box 1 <div class="box2">Box 2 <div class="box3">Box 3</div> </div> </div> </body> </html>
What color is does "Box 3" have?
On a first look, one would be tempted to say 'blue' - but that's not exactly right. While the colour blue is defined after all other properties, it still doesn't apply. When resolving conflicting attribute declarations, the order is not the only one used.
I had a look over the CSS specifications and I came across this interesting paragraph:
3.2 Cascading order
Conflicting rules are intrinsic to the CSS mechanism. To find the value for an element/property combination, the following algorithm must be followed:
1. Find all declarations that apply to the element/property in question. Declarations apply if the selector matches the element in question. If no declarations apply, the inherited value is used. If there is no inherited value (this is the case for the 'HTML' element and for properties that do not inherit), the initial value is used.
2. Sort the declarations by explicit weight: declarations marked '!important' carry more weight than unmarked (normal) declarations.
3. Sort by origin: the author's style sheets override the reader's style sheet which override the UA's default values. An imported style sheet has the same origin as the style sheet from which it is imported.
4. Sort by specificity of selector: more specific selectors will override more general ones. To find the specificity, count the number of ID attributes in the selector (a), the number of CLASS attributes in the selector (b), and the number of tag names in the selector (c). Concatenating the three numbers (in a number system with a large base) gives the specificity. Some examples:LI {...} /* a=0 b=0 c=1 -> specificity = 1 */
UL LI {...} /* a=0 b=0 c=2 -> specificity = 2 */
UL OL LI {...} /* a=0 b=0 c=3 -> specificity = 3 */
LI.red {...} /* a=0 b=1 c=1 -> specificity = 11 */
UL OL LI.red {...} /* a=0 b=1 c=3 -> specificity = 13 */
#x34y {...} /* a=1 b=0 c=0 -> specificity = 100 */Pseudo-elements and pseudo-classes are counted as normal elements and classes, respectively.
5. Sort by order specified: if two rules have the same weight, the latter specified wins. Rules in imported style sheets are considered to be before any rules in the style sheet itself.
Thus, in our case, the confusion is caused by different specificity levels. While sometimes specifity might seem natural (e.g. selecting elements by ID), other times it can lead to confusion. I think the above five rules play a very important role - too bad that most CSS guides and tutorials don't mention these bits.