Printed from TeacherJohn.com • http://teacherjohn.com/tutorials/cascade.php

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
:hover
[id="attributename"]
element (type) selector
pseudo-element selector
0,0,0,1
0,0,0,1
p
:first-letter
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:

So we have the following four specificities:

  1. First we add together the values in the first column: 0 + 0 + 0 + 0 = 0.
  2. Then we add together the values in the second column: 1 + 0 + 0 + 0 = 1.
  3. Then we add together the values in the third column: 0 + 1 + 0 + 0 = 1.
  4. 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

  1. First, the browser examines all styles applying to the page.
    1. 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).
    2. All style declarations selected for a given element are applied to the element.
    3. If no style declaration is specified for a given element, any inherited properties are applied.
    4. If there are no inherited properties for a given element, the "initial values" are applied.
  2. Next, the browser sorts by weight and origin.
    1. !important statements are applied.
      1. Any !important declarations in a user style sheet have the highest weight and overrule everything. Period.
      2. Next, !important declarations in author style sheets overrule everything else.
    2. If no !important statements are specified, the browser sorts by origin:
      1. Author (Web designer) style sheets overrule user style sheets (except user !important statements).
      2. User (reader) style sheets overrule browser (user agent) default style sheets.
      3. If there is no author or user style defined for a given element, the browser default style sheet declaration is applied.
    3. (Note that declaring a shorthand property (such as "background") to be !important is equivalent to declaring all of its sub-properties to be !important.)
  3. Next, if the weights are equal, the browser sorts by specificity.
    1. 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).
    2. (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.)
    3. (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.)
    4. (Note that the rules of specificity differ slightly in CSS 1, CSS 2, and CSS 2.1.)
  4. Next, if specificities are equal, the browser sorts by order.
    1. Internal style sheets overrule external style sheets.
    2. 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.
    3. 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.
    4. (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: