-
Featured Columnists
- Faruk Ateş
- Andy Clarke
- Kris Hadlock
- Robert Hoekman, Jr.
-
Molly Holzschlag
- 10 Steps to CSS Success: Browser, User, Author
- Like Mother Like Child: A Look at Inheritance in CSS
- Using Specificity to Resolve Conflicts
- Box Model Mastery
- Breaking Out of the Box: Using Abstract Thought to Inspire Progressive Web Design
- Microformats: Tomorrow’s Web Today
- Microformats: Managing Personal and Event Data
- Microformats: Understanding Elemental Microformats
- Transcendent CSS: Creating the Aesthetic Web
- Sarah Horton
- Miraz Jordan
- Jonathan and Lisa Price
- Catherine Seda
- Dave Shea
- Dave Taylor
-
Table of Contents
- Welcome
- Web Basics
- Publishing on the Web: Putting Files on the Server
- Web Design Process and Workflow
- Project Management
- Mark My WWWord: HTML and XHTML
- Standards Compliance
- Layouts
- Forms
- Meta Tags and Search
- Usability
- Accessibility
- Enhancing Web Page Interaction
- Web Graphics
- Web Page Optimization
- Multimedia
- Content
- Overview of Servers
- Server Programming Basics
- Careers in Web Design
- Tools
- Tutorials
- Intellectual Property for Web Designers
Using Specificity to Resolve Conflicts
Last updated Oct 17, 2003.
By Molly Holzschlag
There have been countless times prior to learning about specificity that I found myself shaking my fist at myself, Web browsers, and at CSS itself. There I'd be, trying to figure out why a style rule that I'd checked and checked again wasn't being applied properly.
As you are well aware, CSS has multiple means of sorting out how rules within a style sheet are applied. The same is true for multiple style sheets related to a given document. Origin, or which type of style sheet the rule is in; and source order, where the rule exists within a given sheet, each play a role in determining which rule wins.
In this article, I'll briefly review origin and source order, and then discuss specificity. The final means of resolving conflicts in CSS, specificity is a bit of math that browsers use to figure out which rule will ultimately apply.
Origin and Source Order
Many readers will already be familiar with origin. Origin is what kind of style sheet the rules are originating from. For example, if you have an embedded style sheet and a linked style sheets, and each has a rule that conflicts, it is the origin of the rule that will determine whether it wins. Because embedded style overrides linked style, a rule in an embedded style sheet will take precedence over a conflicting rule in a linked sheet (Example 1).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Example 1</title>
<style type="text/css">
h1 { color : red; }
</style>
<link rel="stylesheet" src="mystyle.css" media="screen" />
</head>
<body>
<h1>What color header am I?</h1>
</body>
</html>
mystyle.css
h1 {color : blue; }
In this case, the h1 is going to be red, not blue, because the embedded style takes precedence in terms of the rule's origin.
Source order works similarly, but in the context of style rules within a given style sheet and in the case of multiple styles.
Consider the following example, in which an embedded style sheet contains two conflicting rules:
<style type="text/css">
h1 { color : red; }
h1 { color : blue; }
</style>
In this case, the h1 color will be blue, not red, because the browser will sort rules by a "last one wins" method. Some people like to describe this as "the rule closest to the content applies."
Source order also applies to multiple style sheets within a document. Assume that the following snippet each has an h1 rule with a color defined in relation to its name:
<link rel="stylesheet" src="h1blue.css" media="screen" /> <link rel="stylesheet" src="h1red.css" media="screen" /> <link rel="stylesheet" src="h1green.css" media="screen" />
Here, green will apply to the h1 element, because it is the style closest to the content.
Understanding Specificity
Origin and source order are pretty straightforward concepts, and so long as you keep the idea that a rule closest to the content is the one that will apply, you'll be able to find conflicts and repair them with ease.
But what happens when we have style that has the same origin and source, but the conflict is within the way the rule is written? Consider example 2:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Example 1</title>
<style type="text/css">
h2 { color : blue; }
h2.warning { color : red }
</style>
</head>
<body>
<h2 class="warning">What color header am I?</h2>
</body>
</html>
The h2 color is set to blue, but there's a class added that causes a conflict in styles. In this instance, the rule is later modified with a class.
But here's the twist: If you switch the source order around, the header remains red:
<style type="text/css">
h2.warning { color : red }
h2 { color : blue; }
</style>
The reason is that the h2.warning selector is more specific. That is, it is more exact than the h2 selector. Because of this detail, the source order becomes unimportant and the browser calculates the more specific rule as being the one that is applied.
Math Time
For those non-technical folks out there, I really hate to do this to you, but in order to calculate specificity, we have to do some math.
Specificity calculates how specific a given selector is by counting up what makes up the selector, comparing it to a potential conflicting selector, and seeing which value is in fact more specific.
If you're trying to figure out how specific a selector is, the first thing to do is to create a grid as I have in Table 1, and fill in the actual selector as follows:
|
Selector Example |
# of ID selectors |
# of class selectors |
# of Element (type) selectors |
|
h2 |
|
|
|
|
h2.warning |
|
|
|
|
#content h2 |
|
|
|
|
#content h2.warning |
|
|
|
Now, count up what you have in each column as I've done here in Table 2:
|
Selector Example |
# of ID selectors |
# of class selectors |
# of Element (type) selectors |
|
h2 |
0, |
0, |
1 |
|
h2.warning |
0, |
1, |
1 |
|
#content h2 |
1, |
0, |
1 |
|
#content h2.warning |
1, |
1, |
1 |
Clearly, the #content h2.warning selector is more specific. Therefore, should the declaration(s) associated with that selector conflict with any of the other h2 rules in this example, the style for that particular rule will take precedence.
You'll see that I've placed a comma between my values. Some people say "Oh, just write it out in base 10, because then it would be 1, 11, 101, and 111 respectively and it's really clear now!" That would all be well and good if there wasn't the chance we'd have more than 10 of anything, because that's when the algorithm breaks down if we're interpreting it as base 10.
The specificity algorithm doesn't use base 10, rather a "broad base" (whatever that means!)so it's best to calculate specificity with the commas intact, understanding that 0,0,1 is less specific than 1,1,1.
Inline Style and Specificity
As you might recall from previous articles, inline style always takes precedence over other styles. Inline styles actually factor in to the specificity algorithm.
If, along with these selectors, I've got an inline style within an h2:
<h2 style="float: right; padding-left: 1em; color: orange;">What color am I now?</h2>
Following the terminology in CSS 2.1, I'll need to add an additional 1 to the calculation model, as shown in Table 3.
|
Selector Example |
Inline style present? |
# of ID selectors |
# of class selectors |
# of Element (type) selectors |
|
h2 |
1, |
0, |
0, |
1 |
|
h2.warning |
0, |
0, |
1, |
1 |
|
#content h2 |
0, |
1, |
0, |
1 |
|
#content h2.warning |
0, |
1, |
1, |
1 |
In the case of that particular h2, the color is orange, no matter where else the other styles originate or what their source order is.
Specificity and Specifications
One of the problems with specificity is that every specification of CSS since CSS 1.0 has a somewhat slightly different approach to the algorithm. These inconsistencies, which are very troublesome to browser developers trying to adopt the proper practices, are typically perceived as browser flaws when, in fact, the software engineers have properly implemented a given specification at the point of the browser's development.
Table 4 shows the four existing CSS specifications and how each defines specificity.
|
CSS Version |
How to Calculate |
Treatment of pseudo elements and pseudo classes |
Notes |
|
CSS 1.0 |
Three categories, first count is number of IDs, then classes, then elements |
Calculate pseudo elements as elements; calculate pseudo classes as classes |
Later CSS versions adopt this early approach consistently. |
|
CSS 2.0 |
Three categories, first count is number of IDs, then classes and pseudo classes, then elements |
Ignore pseudo elements |
Pseudo elements are: :first-line :first-letter :before :after |
|
CSS 2.1 |
Four categories, first is inline style, then number of IDs, then any classes and pseudo classes, then elements and pseudo elements |
Calculate pseudo elements as elements |
Doesn't ignore pseudo elements; CSS 2.1 has not yet passed as a recommendation but is becoming widely implemented in browsers despite that fact. |
|
CSS 3.0 |
Three categories, first is number of IDs, then any classes and pseudo classes, then elements |
Ignore pseudo elements |
Goes back to ignoring pseudo elements; calculates inline style separately from specificity; CSS 3.0 is under development |
As you can see, these changes are confusing to anyone. My current advice is to calculate specificity according to CSS 2.1, unless you have pseudo elements involved, in which case if you run into conflicts in certain browsers, don't count them and recalculate.
A Peaceful Resolution
Should you find yourself pulling out hair or breaking down in tears (as often happens to me) because you can't figure out why your h2's aren't turning orange, follow these steps:
- Check your syntax. Is there a problem in your style somewhere? A quick run through a CSS validator can help pinpoint any syntax errors. Find some? Repair those first.
- Check the origin of the rule. Is there a conflict between rules in different style sheets? Is something overriding the style you're trying to apply? If you find a conflict based on origin, remove the conflicts and rewrite rules accordingly.
- Check your source order. Do you have a source order issue? If so, swap out any conflicting rules or change them in the source to get the desired results.
- Check weight. This relates to the !important declaration, which I discussed in the first article to this series. If an !important declaration exists somewhere within an author document, remove it. In almost all cases the !important declaration should be avoided by authors and reserved for users creating user style sheets.
- Check specificity. If you have done all of the above and still have a conflict, raise the specificity of the questionable rule by adding more detail to the selector and see if it doesn't win out.
In an ideal world, conflicts wouldn't ever arise. Of course, even idealists like me have to come down to reality every now and then. By learning to effectively resolve conflicts, you’ll ultimately improve the strength and integrity of your CSS.
