Publishers of technology books, eBooks, and videos for creative people

Home > Articles > Web Design & Development > Usability

Web Design Reference Guide

Hosted by

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.