CSS Specificity Scoring
Most folks realize what the "cascading" part of Cascading Style Sheets means for styling Web pages. However, some of the inner workings of CSS specificity are lost on many of them.
Specificity In General
First, a refresher in CSS specificity:
There are five sources of style definitions: Browser defaults, HTML Elements, Classes, IDs, and Inline Styles (six if you include user overrides). Each source takes a higher precedence over the previous. For instance, a header tag will have font-size and margins applied by the browser, but these are easily reset by simply declaring something like h2 { font-size: 24px; margin: 10px 0 0; } (an element selector) in your style sheet. This can be taken further with declaring h2.smaller { font-size:16px; }, which will shrink headers with a class of "smaller" (the margins will stay the same, however).
Like with most things, order matters. Especially when dealing with multiple external style sheets (common with just about any content management system, and especially with Drupal), the order that a CSS selector is declared makes a big difference. The latter that definition appears in the chain of selectors, the more likely it is to be the style definition that's actually rendered in the browser.
Selectors can be compounded in order to specifically target an element on a page. For instance, #left-column h2 { color: #900; } will cause certain headers in the left column of your page to be red, but they will otherwise keep any styles declared in h2 { ... }. All other header2 tags will be unaffected. This parent/child relationship is common.
However, the CSS large sites can get confusing fast. Selectors are redeclared for different page types, multiple modules might try to override each other, etc. It's important to understand how to quickly determine which selector will be used beyond simply re-ordering style sheets or nesting your elements.
How Specificity Scoring Works
Think back to grade school, when your teacher was explaining numbers' "places". You have ones, tens, hundreds, etc. CSS specificity works much the same way. Each type of CSS element has a different "place". The only real difference is that when a place reaches 10, it doesn't carry over to the next place.
- HTML Element - Ones
- Class - Tens
- ID - Hundreds
- Inline Styles - Thousands
The selector h2 has a specificity score of 1, while the selector #left-column h2 has a score of 101. So, even if #left-column h2 is declared before h2, styles in #left-column h2 will take precedence.
A more complicated example might be to compare the following:
Assuming this HTML:
<div id="content" class="page">
<div id="left-column">
<h2 class="red">My Header</h2>
</div>
</div>
and this CSS:
#content #left-column h2 {
font-size: 24px;
color: #900;
}
body div.page div#left-column h2.red {
font-size: 64px;
color: #090;
margin: 20px 0;
}
Plenty of developers will assume that because the second selector seems more specific and that it's declared last that the header tag will appear big and green. However, the header will be 24 pixels and Georgia Bulldog red.
This is because the first select has a higher specificity score. The first one has two IDs and an HTML element; for a score of 201. The second one has 4 HTML tags, a class, and an ID; for a score of 114.
However, it's also important to note that the header will have a 20 pixel vertical margin, since the first selector didn't declare any margin. Just because a style has a lower specificity score doesn't mean it's completely ignored.


Comments
Clear explanation
Thanks for the clear explanation of CSS specificity. It doesn't affect the score much, but in the 2nd paragraph, did you mean "The first one has two IDs and *an HTML element*" ?
Good catch
David, yes I did. Thanks for pointing that out. I've updated the post to reflect that. Good catch.
Is there a CSS editor that highlights this?
Tobby - this is clear and useful. It suggests that it would be useful to have a tool that, for a given specific element in a web page, extracts all the css that might apply from a set of stylesheets, and sorts them in descending specificity order. Is there such a beast?
Firebug for Firefox
Have you tried the Firebug plugin for Firefox? It doesn't give you the specificity score, but it does a really good job of showing you what styles are actually being applied (as well as any styles that are overridden) and where they come from (CSS file and line number).
Post new comment