The Cascade (in CSS 2.1)
Which style takes precedence in a conflict?
What happens if two or more CSS rules are in conflict? For example, a style sheet may have a conflict such as:
p { color: red; }
p { color: green; }
Obviously paragraphs cannot be both red and green, so the browser must make a decision as to which declaration has more weight and therefore takes precedence. The above conflict is a simple one, but CSS conflicts can be more complicated and harder to figure out. For example:
div.warning p { color: red; }
body > div p { color: green; }
Now it may not be as easy to determine which of the rules above takes precedence for paragraphs that satisfy both selectors. The algorithm used by the Web browser to decide which declaration takes precedence is known as the cascade. To fully understand how CSS works, you must understand the cascade. The most complicated part of the cascade is specificity.
Specificity
Each type of CSS selector has a specificity value. The following table lists specificity values, from high to low:
Selector | Specificity | Example |
---|---|---|
local style | 1,0,0,0 | <p style="stylename"> |
ID selector | 0,1,0,0 | #idname |
class
selector pseudo-class selector attribute selector |
0,0,1,0 0,0,1,0 0,0,1,0 |
.classname |
element
(type) selector pseudo-element selector |
0,0,0,1 0,0,0,1 |
p |
universal selector | 0,0,0,0 | * |
combinator | has no effect | > , + , or whitespace |
(HTML formatting) | 0,0,0,0 | <font color="red"> |
How specificity of a rule is calculated
To calculate the specificity of a CSS rule, we add up the specificity
values of the component parts of the whole selector. For example, in the following
CSS rule:
div#menu a:hover { color: red; }
we have the following selector:
div#menu a:hover
If we look at the composition of this selector, we have:
- one ID selector (
#menu
) with a specificity of 0,1,0,0 - one pseudo-class selector (
:hover
) with a specificity of 0,0,1,0 - one element selector (
div
) with a specificity of 0,0,0,1 - one element selector (
a
) with a specificity of 0,0,0,1
So we have the following four specificities:
- 0,1,0,0
- 0,0,1,0
- 0,0,0,1
- 0,0,0,1
- First we add together the values in the first column: 0 + 0 + 0 + 0 = 0.
- Then we add together the values in the second column: 1 + 0 + 0 + 0 = 1.
- Then we add together the values in the third column: 0 + 1 + 0 + 0 = 1.
- Then we add together the values in the fourth column: 0 + 0 + 1 + 1 = 2.
So the specificity of the CSS rule's entire selector is 0,1,1,2.
Here is a table of specificity examples:
Selector | Specificity | Selector | Specificity | |
---|---|---|---|---|
* |
0,0,0,0 | #menu ol li |
0,1,0,2 | |
p |
0,0,0,1 | div#menu ol li |
0,1,0,3 | |
div p |
0,0,0,2 | div#menu |
0,1,0,1 | |
div p span |
0,0,0,3 | :hover |
0,0,1,0 | |
body > p |
0,0,0,2 | a:hover |
0,0,1,1 | |
p + p |
0,0,0,2 | li > a:hover |
0,0,1,2 | |
.warning |
0,0,1,0 | #menu li a:hover |
0,1,1,2 | |
p.warning |
0,0,1,1 | div#menu li a:hover |
0,1,1,3 | |
p .warning |
0,0,1,1 | div#menu li + li a:hover |
0,1,1,4 | |
#menu |
0,1,0,0 | a:hover .warning |
0,0,2,1 | |
#menu li |
0,1,0,1 | div#menu a:hover > .warning |
0,1,2,2 |
How specificity values are compared
As part of the cascade, the browser reads the specificity of conflicting rules from left to right, comparing each of the four values separately, until it finds one value higher than the other. For example, let's say we have the values of 0,0,3,2 and 0,0,2,4. Which is higher?
The first value is 0 for both, so next we look at each second value, which again is 0 for both. Looking at each third value, we see that one of the values is 3 and the other is 2. We can stop now, and don't need to compare fourth values. So the 0,0,3,2 is higher (considered to have more weight) than the value 0,0,2,4.
The cascade, step-by-step
- First, the browser examines all styles applying to the page.
- The browser finds all CSS rules (including
external, internal, and local styles; browser
defaults; HTML formatting; etc.)
that select a given element (for example,
all
rules
that
select
<p>
elements). - All style declarations selected for a given element are applied to the element.
- If no style declaration is specified for a given element, any inherited properties are applied.
- If there are no inherited properties for a given element, the "initial values" are applied.
- The browser finds all CSS rules (including
external, internal, and local styles; browser
defaults; HTML formatting; etc.)
that select a given element (for example,
all
rules
that
select
- Next, the browser sorts by weight and origin.
!important
statements are applied.- Any
!important
declarations in a user style sheet have the highest weight and overrule everything. Period. - Next,
!important
declarations in author style sheets overrule everything else.
- Any
- If no
!important
statements are specified, the browser sorts by origin:- Author (Web designer) style sheets overrule user style sheets (except
user
!important
statements). - User (reader) style sheets overrule browser (user agent) default style sheets.
- If there is no author or user style defined for a given element, the browser default style sheet declaration is applied.
- Author (Web designer) style sheets overrule user style sheets (except
user
- (Note that declaring a shorthand
property (such as "
background
") to be!important
is equivalent to declaring all of its sub-properties to be!important
.)
- Next, if the weights are equal, the browser sorts by specificity.
- Higher specificity overrules lower specificity (We read the specificity from left to right, comparing each of the four values separately, until we find one value higher than the other).
- (Note that what the CSS specifications call "non-CSS presentational hints" — HTML formatting — are converted to corresponding CSS rules with specificity of 0. These rules are assumed to be at the start of the author style sheet and may be overridden by subsequent style sheet rules.)
- (Note that inheritance has no specificity, which is not the same as having a specificity of 0. This means that even a specificity of 0 will overrule inheritance. In other words, simply applying a property to an element overrules inheritance.)
- (Note that the rules of specificity differ slightly in CSS 1, CSS 2, and CSS 2.1.)
- Next, if specificities are equal, the browser sorts by order.
- Internal style sheets overrule external style sheets.
- A style sheet that imports a style sheet into itself carries more weight than, and overrules, the imported styles. If more than one sheet is imported they will cascade in the order in which they are imported: the last imported style sheet will overrule the next to last, and so on.
- If the weights are equal in a given style sheet or page, the later a declaration appears in the style sheet or page, the greater its weight.
- (Note that local styles have the highest specificity, so they always
overrule internal and external style sheets, unless those style sheets
contain
!important
rules.)
A cascade example
Let's say the HTML looks like this:
<body text="maroon">
<div class="warning">
<p>This is a paragraph.</p>
</div>
</body>
And an external style sheet contains these rules:
div.warning p { color: red; }
body > div p { color: green; }
Will the paragraph be maroon, red, or green? First, the browser finds that both CSS rules, as well as the HTML text attribute, apply to this paragraph, which means we have a conflict. Because the HTML formatting says that the body is maroon, and because the paragraph is a descendent of the body, the principle of inheritance would normally cause the paragraph text to be maroon. But inheritance is always easily overruled; both selectors in the style sheet select this paragraph, so the inheritance of maroon will be overruled. It is less clear how the conflict between the two CSS rules will play out.
Next, the browser sorts by weight and origin. It finds no weighty !important
statements apply to this paragraph, so it now looks at the origin of the styles.
Because both CSS rules originate in the same external style sheet, their origin
weight is equal. The conflict not yet resolved, the browser goes to the next
step.
Now the browser looks at the specificity of the two selectors that select
the paragraph. The first selector contains two element (sometimes called "type")
selectors (p
and div
), which each have a value of
0,0,0,1; together they add up to 0,0,0,2. And the selector also contains one
class selector (.warning
),
which has a
specificity
of
0,0,1,0.
Adding these
together,
we see that the total specificity of the selector is 0,0,1,2. (Note that the
whitespace between the p
and the .warning
class,
called a descendant combinator, does not affect the specificity calculation.)
The second selector contains a total of three element selectors (p
,
div
, and body
), which add up to 0,0,0,3. (Note that
the > between the div
and the body
, called a child
combinator, does not affect the specificity calculation.)
So we see that the first selector div.warning p
has a specificity
of
0,0,1,2 while the second selector body > div p
has a specificity
of 0,0,0,3. Which specificity value if higher?
We read the specificity from left to right, comparing each of the four values separately, until we find one value higher than the other. The first value is 0 for both, so we next look at each second value, which again is 0 for both. Looking at each third value, we see that one of the values is 1 and the other is 0. So the 0,0,1,2 is higher (considered to have more weight) than the value 0,0,0,3. We can stop now, and don't need to compare fourth values.
And the paragraph's inheritance of the body's attribute value of maroon is considered to have no specificity value at all, so it is overruled by any specificity value, even 0,0,0,0.
In summary:
0,0,1,2 is the specificity of div.warning p { color: red; }
0,0,0,3 is the specificity of body > div p { color: green; }
The paragraph will be red. (Because both rules are in the same style sheet and have unequal weights, the conflict is resolved and there is no need for the browser to sort by order, the otherwise final step of the cascade.)
For more information:
- Assigning property values, Cascading, and Inheritance (W3C specs)
http://www.w3.org/TR/REC-CSS2/cascade.html