DekGenius.com
Previous Section  < Day Day Up >  Next Section

3.1 Specificity

You know from Chapter 2 that you can select elements using a wide variety of means. In fact, it's possible that the same element could be selected by two or more rules, each with its own selector. Let's consider the following three pairs of rules. Assume that each pair will match the same element:

h1 {color: red;}
body h1 {color: green;}

h2.grape {color: purple;}
h2 {color: silver;}

html > body table tr[id="totals"] td ul > li {color: maroon;}
li#answer {color: navy;}

Obviously, only one of the two rules in each pair can win out, since the matched elements can be only one color or the other. How do you know which one will win?

The answer is found in the specificity of each selector. For every rule, the user agent evaluates the specificity of the selector and attaches it to each declaration in the rule. When an element has two or more conflicting property declarations, the one with the highest specificity will win out.

This isn't the whole story in terms of conflict resolution. In fact, all style conflict resolution is handled by the cascade, which has its own section later in this chapter.


A selector's specificity is determined by the components of the selector itself. A specificity value is expressed in four parts, like this: 0,0,0,0. The actual specificity of a selector is determined as follows:

  • For every ID attribute value given in the selector, add 0,1,0,0.

  • For every class attribute value, attribute selection, or pseudo-class given in the selection, add 0,0,1,0.

  • For every element and pseudo-element given in the selector, add 0,0,0,1. CSS2 contradicted itself as to whether pseudo-elements had any specificity at all, but CSS2.1 makes it clear that they do, and this is where they belong.

  • Combinators and the universal selector do not contribute anything to the specificity (more on these values later).

For example, the following rules' selectors result in the indicated specificities:

h1 {color: red;}  /* specificity = 0,0,0,1 */
p em {color: purple;}  /* specificity = 0,0,0,2 */
.grape {color: purple;}  /* specificity = 0,0,1,0 */
*.bright {color: yellow;}  /* specificity = 0,0,1,0 */
p.bright em.dark {color: maroon;}  /* specificity = 0,0,2,2 */
#id216 {color: blue;}  /* specificity = 0,1,0,0 */
div#sidebar *[href] {color: silver;}  /* specificity = 0,1,1,1 */

Given a case where an em element is matched by both the second and fifth rules in the example above, that element will be maroon because the fifth rule's specificity outweighs the second's.

As an exercise, let's return to the pairs of rules from earlier in the section, and fill in the specificities:

h1 {color: red;}  /* 0,0,0,1 */
body h1 {color: green;}  /* 0,0,0,2  (winner)*/

h2.grape {color: purple;}  /* 0,0,1,1 (winner) */
h2 {color: silver;}  /* 0,0,0,1 */

html > body table tr[id="totals"] td ul > li {color: maroon;}  /* 0,0,1,7 */
li#answer {color: navy;}  /* 0,1,0,1  (winner) */

You've indicated the winning rule in each pair; in each case, it is because the specificity is higher. Notice how they're sorted. In the second pair, the selector h2.grape wins because it has an extra one: 0,0,1,1 beats out 0,0,0,1. In the third pair, the second rule wins because 0,1,0,1 wins out over 0,0,1,7. In fact, the specificity value 0,0,1,0 will win out over the value 0,0,0,13.

This happens because the values are sorted from left to right. A specificity of 1,0,0,0 will win out over any specificity that begins with a 0, no matter what the rest of the numbers might be. So 0,1,0,1 wins over 0,0,1,7 because the 1 in the first value's second position beats out the second 0 in the second value.

3.1.1 Declarations and Specificity

Once the specificity of a selector has been determined, the value will be conferred on all of its associated declarations. Consider this rule:

h1 {color: silver; background: black;}

For specificity purposes, the user agent must treat the rule as if it were "ungrouped" into separate rules. Thus, the previous example would become:

h1 {color: silver;}
h1 {background: black;}

Both have a specificity of 0,0,0,1, and that's the value conferred on each declaration. The same splitting-up process happens with a grouped selector as well. Given the rule:

h1, h2.section {color: silver; background: black;}

the user agent treats it as follows:

h1 {color: silver;}  /* 0,0,0,1 */
h1 {background: black;}  /* 0,0,0,1 */
h2.section {color: silver;}  /* 0,0,1,1 */
h2.section {background: black;}  /* 0,0,1,1 */

This becomes important in situations where multiple rules match the same element and where some declarations clash. For example, consider these rules:

h1 + p {color: black; font-style: italic;}  /* 0,0,0,2 */
p {color: gray; background: white; font-style: normal;}  /* 0,0,0,1 */
*.aside {color: black; background: silver;}  /* 0,0,1,0 */

When applied to the following markup, the content will be rendered as shown in Figure 3-1:

<h1>Greetings!</h1>
<p class="aside">
It's a fine way to start a day, don't you think?
</p>
<p>
There are many ways to greet a person, but the words are not as important as the act 
of greeting itself.
</p>
<h1>Salutations!</h1>
<p>
There is nothing finer than a hearty welcome from one's fellow man.
</p>
<p class="aside">
Although a thick and juicy hamburger with bacon and mushrooms runs a close second.
</p>
Figure 3-1. How different rules affect a document
figs/css2_0301.gif

In every case, the user agent determines which rules match an element, calculates all of the associated declarations and their specificities, determines which ones win out, and then applies the winners to the element to get the styled result. These machinations must be performed on every element, selector, and declaration. Fortunately, the user agent does it all automatically. This behavior is an important component of the cascade, which we will discuss later in this chapter.

3.1.2 Universal Selector Specificity

As was stated earlier, the universal selector does not contribute to the specificity of a selector. In other words, it has a specificity of 0,0,0,0, which is different than having no specificity (as we'll discuss in Section 3.2). Therefore, given the following two rules, a paragraph descended from a div will be black, but all other elements will be gray:

div p {color: black;}  /* 0,0,0,2 */
* {color: gray;}  /* 0,0,0,0 */

As you might expect, this means that the specificity of a selector that contains a universal selector along with other selectors is not changed by the presence of the universal selector. The following two selectors have exactly the same specificity:

div p  /* 0,0,0,2 */
body * strong  /* 0,0,0,2 */

Combinators, by comparison, have no specificity at all—not even zero specificity. Thus, they have no impact on a selector's overall specificity.

3.1.3 ID and Attribute Selector Specificity

It's important to note the difference in specificity between an ID selector and an attribute selector that targets an id attribute. Returning to the third pair of rules in the example code, we find:

html > body table tr[id="totals"] td ul > li {color: maroon;}  /* 0,0,1,7 */
li#answer {color: navy;}  /* 0,1,0,1  (winner) */

The ID selector (#answer) in the second rule contributes 0,1,0,0 to the overall specificity of the selector. In the first rule, however, the attribute selector ([id="totals"]) contributes 0,0,1,0 to the overall specificity. Thus, given the following rules, the element with an id of meadow will be green:

#meadow {color: green;}  /* 0,1,0,0 */
*[id="meadow"] {color: red;}  /* 0,0,1,0 */

3.1.4 Inline Style Specificity

So far, we've seen specificities that begin with a zero, so you may be wondering why it's there at all. As it happens, that first zero is reserved for inline style declarations, which trump any other declaration's specificity. Consider the following rule and markup fragment:

h1 {color: red;}

<h1 style="color: green;">The Meadow Party</h1>

Given that the rule is applied to the h1 element, you would still probably expect the text of the h1 to be green. This is what happens in CSS2.1, and it happens because every declaration has a specificity of 1,0,0,0.

This means that even elements with id attributes that match a rule will obey the inline style declaration. Let's modify the previous example to include an id:

h1#meadow {color: red;}

<h1 id="meadow" style="color: green;">The Meadow Party</h1>

Thanks to the inline declaration's specificity, the text of the h1 element will still be green.

The primacy of inline style declarations is new to CSS2.1, and it exists to capture the state of web browser behavior at the time CSS2.1 was written. In CSS2, the specificity of an inline style declaration was 1,0,0 (as CSS2 specificities have three values, not four). In other words, it had the same specificity as an ID selector, which would have easily overridden inline styles.


3.1.5 Importance

Sometimes, a rule is so important that it outweighs all other considerations. CSS2.1 calls these important rules (for obvious reasons) and lets you mark them by inserting the phrase !important just before the terminating semicolon in a rule:

p.dark {color: #333 !important; background: white;}

Here, the color value of #333 is marked !important, whereas the background value of white is not. If you wish to mark both rules as important, each rule will need its own !important:

p.dark {color: #333 !important; background: white !important;}

You must place !important correctly, or the rule may be invalidated. !important always goes at the end of the declaration, right before the semicolon. This placement is especially important—no pun intended—when it comes to properties that allow values containing multiple keywords, such as font:

p.light {color: yellow; font: smaller Times, serif !important;}

If !important were placed anywhere else in the font declaration, the entire declaration would likely be invalidated and none of the styles applied.

Declarations that are marked !important do not have a special specificity value, but are instead considered separately from nonimportant rules. In effect, all !important declarations are grouped together and specificity conflicts are resolved relative to each other. Similarly, all nonimportant declarations are considered together, with property conflicts resolved using specificity. In any case where an important and a nonimportant declaration conflict, the important declaration always wins.

The result of the following rules and markup fragment is illustrated in Figure 3-2:

h1 {font-style: italic; color: gray !important;}
.title {color: black; background: silver;}
* {background: black !important;}

<h1 class="title">NightWing</h1>
Figure 3-2. Important rules always win
figs/css2_0302.gif

Important rules and their handling are discussed in more detail in Section 3.3, later in this chapter.


    Previous Section  < Day Day Up >  Next Section