CSS: The Definitive Guide, 3rd Edition (11 page)

Read CSS: The Definitive Guide, 3rd Edition Online

Authors: Eric A. Meyer

Tags: #COMPUTERS / Web / Page Design

BOOK: CSS: The Definitive Guide, 3rd Edition
11.93Mb size Format: txt, pdf, ePub
Inheritance

As important as specificity may be to understanding how
declarations are applied to a document, another key concept is inheritance.
Inheritance is the mechanism by which
styles are applied not only to a specified element, but also to its descendants. If a
color is applied to an
h1
element, for example, then
that color is applied to all text in the
h1
, even the
text enclosed within child elements of that
h1
:

h1 {color: gray;}
Meerkat Central

Both the ordinary
h1
text and the
em
text are colored gray because the
em
element inherits the value of
color
. If property values could not be inherited by descendant elements,
the
em
text would be black, not gray, and you'd have
to color that element separately.

Inheritance also works well with unordered lists. Let's say you apply a style of
color
:
gray;
for
ul
elements:

ul {color: gray;}

You expect that a style that is applied to a
ul
will also be applied to its list items, and to any content of those list items. Thanks
to inheritance, that's exactly what happens, as
Figure 3-3
demonstrates.

Figure 3-3. Inheritance of styles

It's easier to see how inheritance works by turning to a tree diagram of a document.
Figure 3-4
shows the tree diagram for a
very simple document containing two lists: one unordered and the other ordered.

Figure 3-4. A simple tree diagram

When the declaration
color
:
gray;
is applied to the
ul
element, that element takes on that declaration. The value is then
propagated down the tree to the descendant elements and continues on until there are no
more descendants to inherit the value. Values are
never
propagated
upward; that is, an element never passes values up to its ancestors.

Tip

There is an exception to the upward propagation rule in HTML: background styles
applied to the
body
element can be passed to the
html
element, which is the document's root
element and therefore defines its canvas.

Inheritance is one of those things about CSS that is so basic that you almost never
think about it unless you have to. However, you should still keep a few things in mind.

First, note that some properties are not inherited—generally as a result of simple
common sense. For example, the property
border
(which
is used to set borders on elements) does not inherit. A quick glance at
Figure 3-5
reveals why this is the case. If
borders were inherited, documents would become much more cluttered—unless the author
took the extra effort to turn off the inherited borders.

Figure 3-5. Why borders aren't inherited

As it happens, most of the box-model properties—including margins, padding,
backgrounds, and borders—are not inherited for the same reason. After all, you wouldn't
want all of the links in a paragraph to inherit a 30-pixel left margin from their parent
element!

Inherited values have no specificity at all, not even zero specificity. This seems
like an academic distinction until you work through the consequences of the lack of
inherited specificity. Consider the following rules and markup fragment and compare them
to the result shown in
Figure 3-6
:

* {color: gray;}
h1#page-title {color: black;}
Meerkat Central


Welcome to the best place on the web for meerkat information!


Figure 3-6. Zero specificity defeats no specificity

Inherit the Bugs

Due to problems in various browser implementations, an author cannot rely on
inheritance to operate as expected in all circumstances. For example, Navigator 4
(and, to a lesser extent, Explorer 4 and 5) does not inherit styles into tables.
Thus, the following rule would result in a document with smaller text everywhere
outside of tables:

body {font-size: 0.8em;}

This is not correct behavior under CSS, but it does exist, so authors have
historically resorted to tricks such as:

body, table, th, td {font-size: 0.8em;}

This is more likely, although still not guaranteed, to achieve the desired effect
in buggy browsers.

Unfortunately, the above "fix" leads to an even worse problem in browsers that do
implement inheritance correctly, such as IE6/Win, IE5/Mac, Netscape 6+, and others.
In those browsers, you will end up with text inside a table cell that is 41 percent
of the size of the user's default font size setting. It is often more dangerous to
attempt to work around inheritance bugs in old browsers than it is to write correct
CSS for updated browsers.

Since the universal selector applies to all elements and has zero specificity, its
color declaration's value of
gray
wins out over the
inherited value of
black
, which has no specificity at
all. Therefore, the
em
element is rendered gray
instead of black.

This example vividly illustrates one of the potential problems of using the universal
selector indiscriminately. Because it can match any element, the universal selector
often has the effect of short-circuiting inheritance. This can be worked around, but
it's usually more sensible to avoid the problem in the first place by not using the
universal selector indiscriminately.

The complete lack of specificity for inherited values is not a trivial point. For
example, assume that a style sheet has been written such that all text in a "toolbar" is
to be white on black:

#toolbar {color: white; background: black;}

This will work as long as the element with an
id
of
toolbar
contains nothing but plain text. If,
however, the text within this element is all hyperlinks (
a
elements), then the user agent's styles for hyperlinks will take over. In a
web browser, this means they'll likely be colored blue, since the browser's style sheet
probably contains an entry like this:

a:link {color: blue;}

To overcome this problem, you must declare:

#toolbar {color: white; background: black;}
#toolbar a:link {color: white;}

By targeting the rule directly to the
a
elements
within the toolbar, you'll get the result shown in
Figure 3-7
.

Figure 3-7. Directly assigning styles to the relevant elements

The Cascade

Throughout this chapter, we've skirted one rather
important issue: what happens when two rules of equal specificity apply to the same
element? How does the browser resolve the conflict? For example, say you have the
following rules:

h1 {color: red;}
h1 {color: blue;}

Which one wins? Both have a specificity of
0,0,0,1
, so they have equal weight and should both apply. That simply can't
be the case because the element can't be both red and blue. But which will it be?

Finally, the name "Cascading Style Sheets" makes some sense. CSS is based on a method
of causing styles to cascade together, which is made possible by combining inheritance
and specificity. The cascade rules
for CSS2.1 are simple enough:

  1. Find all rules that contain a selector that matches a given element.

  2. Sort by explicit weight all declarations applying to the element. Those rules
    marked
    !important
    are given higher weight than
    those that are not. Sort by origin all declarations applying to a given element.
    There are three origins: author, reader, and user agent. Under normal
    circumstances, the author's styles win out over the reader's styles.
    !important
    reader styles are stronger than any other
    styles, including
    !important
    author styles.
    Both author and reader styles override the user agent's default styles.

  3. Sort by specificity all declarations applying to a given element. Those
    elements with a higher specificity have more weight than those with lower
    specificity.

  4. Sort by order all declarations applying to a given element. The later a
    declaration appears in the style sheet or document, the more weight it is given.
    Declarations that appear in an imported style sheet are considered to come before
    all declarations within the style sheet that imports them.

To be perfectly clear about how this all works, let's consider three examples that
illustrate the last three of the four cascade rules.

Sorting by Weight and Origin

Under the second rule, if two rules
apply to an element, and one is marked
!important
,
the important rule wins out:

p {color: gray !important;}

Well, hello there!


Despite the fact that there is a color assigned in the
style
attribute of the paragraph, the
!important
rule wins out, and the paragraph is gray. This gray is
inherited by the
em
element as well.

Furthermore, the origin of
a rule is considered. If an element is matched by
normal-weight styles in both the author's style sheet and the reader's style sheet,
then the author's styles are used. For example, assume that the following styles come
from the indicated origins:

p em {color: black;}    /* author's style sheet */
p em {color: yellow;} /* reader's style sheet */

In this case, emphasized text within paragraphs is colored black, not yellow,
because normal-weight author styles win out over normal-weight reader styles.
However, if both rules are marked
!important
, the
situation changes:

p em {color: black !important;}    /* author's style sheet */
p em {color: yellow !important;} /* reader's style sheet */

Now the emphasized text in paragraphs will be yellow, not black.

As it happens, the user agent's default styles—which are often influenced by the
user preferences—are figured into this step. The default style declarations are the
least influential of all. Therefore, if an author-defined rule applies to anchors
(e.g., declaring them to be
white
), then this rule
overrides the user agent's defaults.

To sum up, there are five levels to consider in terms of declaration weight. In
order of most to least weight, these are:

  1. Reader important declarations

  2. Author important declarations

  3. Author normal declarations

  4. Reader normal declarations

  5. User agent declarations

Authors typically need to worry about only the first four weight levels, since
anything declared will win out over the user agent styles.

Sorting by Specificity

According to the third rule, if conflicting
declarations apply to an element and they all have the same weight, they should be
sorted by specificity, with the most specific declaration winning out. For example:

p#bright {color: silver;}
p {color: black;}

Well, hello there!


Given the rules shown, the text of the paragraph will be silver, as illustrated in
Figure 3-8
. Why? Because the
specificity of
p#bright (0,1,0,1)
overrode the
specificity of
p (0,0,0,1)
, even though the latter
rule comes later in the style sheet.

Figure 3-8. Higher specificity wins out over lower specificity

Sorting by Order

Finally, under the fourth rule, if two rules
have exactly the same weight, origin, and specificity, then the one that occurs later
in the style sheet wins out. Therefore, let's return to our earlier example, where we
find the following two rules in the document's style sheet:

h1 {color: red;}
h1 {color: blue;}

Because its rule comes later in the style sheet, the value of
color
for all
h1
elements in the document will be
blue
, not
red
. Any rule that is contained in the document
with a higher weight than the imported rule wins out. This is true even if the rule
is part of the document's style sheet and not part of an element's
style
attribute. Consider the following:

p em {color: purple;}  /* from imported style sheet */
p em {color: gray;} /* rule contained within the document */

In this case, the second rule shown will win out over the imported rule because it
is a part of the document's style sheet.

For the purposes of this rule, styles specified in the
style
attribute of an element are considered to be at the end of the
document's style sheet, which places them after all other rules. However, this is a
largely academic point, since inline
style declarations have a
higher specificity than any style sheet selector in CSS2.1.

Tip

Remember that in CSS2, inline style declarations have a specificity equal to ID
selectors. In a CSS2 (but not CSS2.1) user agent,
style
attribute declarations are considered to appear at the end of the
document's style sheet and are sorted by weight, origin, specificity, and order as
with any other declaration in the style sheet.

Order sorting is the reason behind the often-recommended ordering of link styles.
The recommendation is that you array your link styles in the order
link-visited-hover-active, or LVHA, like this:

:link {color: blue;}
:visited {color: purple;}
:hover {color: red;}
:active {color: orange;}

Thanks to the information in this chapter, you now know that the specificity of
all of these selectors is the same:
0,0,1,0
.
Because they all have the same weight, origin, and specificity, the last one that
matches an element will win out. An unvisited link that is being "clicked" is matched
by three of the rules—
:link
,
:hover
, and
:active
—so the last one of those three declared will win out. Given the
LVHA ordering,
:active
will win, which is likely
what the author intended.

Assume for a moment that you decide to ignore the common ordering and alphabetize
your link styles instead. This would yield:

:active {color: orange;}
:hover {color: red;}
:link {color: blue;}
:visited {color: purple;}

Given this ordering, no link would ever show
:hover
or
:active
styles because the
:link
and
:visited
rules come after the other two. Every link must be either visited
or unvisited, so those styles will always override the
:hover
rule.

Let's consider a variation on the LVHA order that an author might want to use. In
this ordering, only unvisited links will get a hover style; visited links do not.
Both visited and unvisited links will get an active style:

:link {color: blue;}
:hover {color: red;}
:visited {color: purple;}
:active {color: orange;}

Of course, sometimes such conflicts arise when all the states attempt to set the
same property. If each state styles a different property, then the order does not
matter. In the following case, the link styles could be given in any order and would
still function:

:link {font-weight: bold;}
:visited {font-style: italic;}
:hover {color: red;}
:active {background: yellow;}

You may also have realized that the order of the
:link
and
:visited
styles doesn't
matter. You could order the styles LVHA or VLHA with no ill effect. However, LVHA
tends to be preferred because it was recommended in the CSS2 specification and also
because the mnemonic "LoVe—HA!" gained rather wide currency. (There's some bitterness
out there, apparently.)

The ability to chain pseudo-classes together eliminates these worries. The
following could be listed in any order without any negative effects:

:link {color: blue;}
:visited {color: purple;}
:link:hover {color: red;}
:visited:hover {color: gray;}

Because each rule applies to a unique set of link states, they do not conflict.
Therefore, changing their order will not change the styling of the document. The last
two rules do have the same specificity, but that doesn't matter. A hovered unvisited
link will not be matched by the rule regarding hovered visited links, and vice versa.
If we were to add active-state styles, then order would start to matter again.
Consider:

:link {color: blue;}
:visited {color: purple;}
:link:hover {color: red;}
:visited:hover {color: gray;}
:link:active {color: orange;}
:visited:active {color: silver;}

If the active styles were moved before the hover styles, they would be ignored.
Again, this would happen due to specificity conflicts. The conflicts could be avoided
by adding more pseudo-classes to the chains, like this:

:link:hover:active {color: orange;}
:visited:hover:active {color: silver;}

Chained pseudo-classes, which lessen worries about specificity and ordering, would
be used much more often if Internet Explorer had historically supported them. (See
Chapter 2
for more information on this
subject.)

Non-CSS Presentational Hints

It is possible that a document will contain presentational
hints that are not CSS—e.g., the
font
element.
Non-CSS hints are treated as if they have a specificity of
0
and appear at the
beginning
of the author's style
sheet. Such presentation hints will be overridden by any author or reader styles, but
not by the user agent's styles.

Other books

The Shape of Desire by Sharon Shinn
What This Wolf Wants by Jennifer Dellerman
Twins of Prey by W.C. Hoffman
The Key in the Attic by DeAnna Julie Dodson
Silencer by Campbell Armstrong
Collide by Megan Hart