Monday 20 June 2011

The CSS Cascade and Specificity

NOTE: This post is an extract from CSS Mastery: Advanced Web Standards Solutions, by Andy Budd If you find this post useful...Buy The Book!!!

The Cascade and Specificity

With even a moderately complicated style sheet, it is likely that two or more rules will target the same element. CSS handles such conflicts through a process known as the cascade. The cascade works by assigning an importance to each rule. Author style sheets are those written by the site developers and are considered the most important. Users can apply their own styles via the browser and these are considered the next most important. Finally, the default style sheets used by your browser or user agent are given the least importance so you can always override them. To give users more control, they can override any rule by specifying it as !important even a rule flagged as !important by the author. This is to allow for specific accessibility needs such as using a medium contrast user style sheet if you have a certain forms of dyslexia.
So the cascade works in the following order of importance:
  • User styles flagged as !important
  • Author styles flagged as !important
  • Author styles
  • User styles
  • Styles applied by the browser/user agent
Rules are then ordered by how specific the selector is. Rules with more specific selectors override those with less specific ones. If two rules are equally specific, the last one defined takes precedence.

Specificity

To calculate how specific a rule is, each type of selector is assigned a numeric value. The specificity of a rule is then calculated by adding up the value of each of its selectors. Unfortunately, specificity is not calculated in base 10 but a high, unspecified, base number. This is to ensure that a highly specific selector, such as an ID selector, is never overridden by lots of less specific selectors, such as type selectors. However, if you have fewer than 10 selectors in a specific selector, you can calculate specificity in base 10 for simplicity's sake.
The specificity of a selector is broken down into four constituent levels: a, b, c, and d.
  • If the style is an inline style, a equals 1.
  • b equals the total number of ID selectors.
  • c equals the number of class, pseudo-class, and attribute selectors.
  • d equals the number of type selectors and pseudo-element selectors.
Using these rules, it is possible to calculate the specificity of any CSS selector. Table 2-1 shows a series of selectors, along with their associated specificity.

Table 2-1: Specificity examples
Selector
Specificity
Specificity in Base 10
Style=""
1,0,0,0
1000
#wrapper #content {}
0,2,0,0
200
#content .datePosted {}
0,1,1,0
110
div#content {}
0,1,0,1
101
#content {}
0,1,0,0
100
p.comment .dateposted {}
0,0,2,1
21
p.comment{}
0,0,1,1
11
div p {}
0,0,0,2
2
p {
0,0,0,1
1


At first glance, all this talk of specificity and high but undefined based numbers may seem a little confusing, so here's what you need to know. Essentially, a rule written in a style attribute will always be more specific than any other rule. A rule with an ID will be more specific than one without an ID, and a rule with a class selector will be more specific than a rule with just type selectors. Finally, if two rules have the same specificity, the last one defined prevails.

Specificity can be extremely important when fixing bugs, as you need to know which rules take precedence and why. For instance, say you had this set of rules. What color do you think the two headlines will be?
 
#content div#main-content h2 {
  color: gray;
}
#content #main-content>h2 {
  color: blue;
}
body #content div[id="main-content"] h2 {
  color: green;
}
#main-content div.news-story h2 {
  color: orange;
}

#main-content [class="news-story"] h2 {
  color: yellow;
}
div#main-content div.news-story h2.first {
  color: red;
}

<div id="content">
 <div id="main-content">
    <h2>Strange Times</h2>
      <p>Here you can read bizarre news stories from around the globe.</p>
  <div class="news-story">
    <h2 class="first">Bog Snorkeling Champion Announced Today</h2>
      <p>The 2008 Bog Snorkeling Championship was won by Conor MurphyImage from book
      with an impressive time of 1 minute 38 seconds.</p>
  </div>
 </div>
</div>
The answer, surprisingly, is that both headlines are gray. The first selector has the highest specificity because it's made up of two ID selectors. Some of the later selectors may look more complicated, but as they only contain one ID, they will always lose out against the more specific selectors.

If you ever come across a CSS rule that just doesn't seem to be working, you could be suffering from a specificity clash. Try making your selectors more specific by adding the ID of one of its parents. If that fixes the problem, you'll probably find that there is a more specific rule somewhere in your style sheet overriding what you're trying to do. If that's the case, you'll probably want to go back through your code and clean up the specificity clashes to keep your code as lean as possible.

No comments:

Post a Comment