Cascading is the process by which a style system determines which value for each property to apply to each element. There are four rules in the process of cascading.
For a style rule to apply to an element, its selector must match the element. If there is only one declaration for a given property with a selector that matches an element, then that declaration applies, without question. If multiple declarations match the element, then the declaration that applies is determined by weight and origin, specificity, or order, as explained below.
If there is no declaration for a given property with a selector that matches the element, then the value for that property is set to its default value (as defined in the CSS specification). This default value could be one of three things.
margin-left
property, which is 0
by default).
font-family
property), which means that the value of the property is taken from
the computed value of that property on the parent element (with a few
exceptions).
border-top-color
property, which by default takes the value of the color
property).
Newer versions of CSS are making it possible to specify
explictly more of these defaults. In CSS1, the only thing that
a stylesheet could state explicitly was the first possibility
above, a value. That is, in CSS1, explicit values were the
only defaults that, when overrided, could be returned to the
default with a rule higher in the cascade. In CSS2, one can
explicitly give the second behavior using the
inherit
keyword. Perhaps in future versions of
CSS it will be possibly to specify that properties inherit from
the values of other properties. (Note, however, that the
default behavior of the border-*-color
properties
can be obtained using the shorthand
border properties.)
In a user or an author stylesheet, a declaration may be given the weight
!important
, by placing !important
(with
optional whitespace on either side of the !
) after the
property's value, like this:
body { color: black ! important; background-color: white!important; }
This weight controls the declaration's place in the cascade. Of all the declarations for a given property that match an element, the one that is chosen must be one of those in the highest category in the following list:
!important
!important
(Note: In CSS1, author-important
declarations were more important than user-important
declarations. This
was changed in CSS2. Some browsers support the CSS1 rules.
Therefore, authors should avoid using
!important
so that users with disabilities can
still access all pages.)
If there are multiple declarations for a given property in the highest of these groups that exists, then the declarations below are used to choose the value that is applied. For example, if there are three author declarations that match a given element (and no user-important or author-important declarations), then specificity (and maybe even order) must be used to find which rule applies.
Specificity is a number derived from a rule's selector (in an arbitrary large number base, not in base ten) that tells which declaration is applied. Specificity is used only when multiple rules have selectors that match the element and no rule has the unique heighest weight/origin combination. The specificity is used to determine which rules of those with the highest weight/origin combination of those rules whose selectors match the element.
The specificity of a selector is calculated as follows. It is the
number abc
where a
is the number of id
selectors in the selector, b
is the number of
pseudo-classes and attribute selectors (including class selectors),
and c
is the number of element names in the selector.
An inline style element also has specificity 100 (and is assumed to
be after any other rules), but I have proposed
that this be changed, partly because browsers treat it as if it had
specificity 1000. For example, the following selectors have the
specificities given:
Selector | Specificity |
---|---|
* |
0 |
h1 |
1 |
body table > thead > tr + tr |
5 |
UL LI OL LI OL LI UL LI UL LI UL LI |
c |
.warning |
10 |
table code.usercss |
12 |
div[lang=en][class=warning] > h1[lang=fr] |
32 |
A:link *[alt=""][border=0][class="warning"] |
41 |
#head H1 + P |
102 |
Note that grouping of selectors does not change specificity. If the
selector is h3, h4.warn, h5#error
, the specificity is
still 1 if the element matched is an h3
, 11 if the
element matched is an h4
with class="warn"
,
and 110 if the element matched is an h5
with
id="error"
.
If there are still multiple declarations of the same property that match an element and have the same weight, the same origin, and the same specificity, then the last one wins. This finally determines which value is applied. You may think this one doesn't get used much, but that isn't true. It is often needed so that (for example) pseudo-classes that are not mutually exclusive work correctly. For example, the following doesn't do what is intended:
a:hover { color: red; } a:link { color: blue; } /* overrides a:hover for unvisited links */ a:visited { color: purple; } /* overrides a:hover for visited links */
The a:hover
rule needs to be placed after the other two
so that it will cascade over them.
Also, it is often useful to define the same rule twice in one ruleset, for example:
body { font: 16px/1.5 "Times New Roman", Times, serif; /* sets a number of properties to their default value, including font-size-adjust */ font-size-adjust: 0.45; }
This section (as is the section on selectors) is based partially on an article I wrote on comp.infosystems.www.authoring.html.
Non-CSS presentational hints are, according to CSS2, translated into the corresponding CSS rules and treated as if they occurred at the beginning of the CSS style sheet with specificity zero. This means that appropriate CSS declarations in the author style sheet always override them (as do !important declarations in the user stylesheet).
However, the important question is what author declarations override them. The answer to this question comes from the way CSS selectors work. Selectors match elements in the document tree. The default (which is often to inherit from the parent) only occurs when no selector matches the element.
Now, what does this mean for non-CSS presentational hints? It means that they can always be overridden by author CSS that acts on the HTML element that provides the presentational hint. For example, the ruleset:
font { color: inherit; font-size: inherit; font-family: inherit; }
in an author stylesheet will neutralize all font
elements (assuming that "inherit" works, which it doesn't in some
browsers.) To do this in a user stylesheet, one would need to use
the weight "! important
":
font { color: inherit ! important; font-size: inherit ! important; font-family: inherit ! important; }
However, styling an element that occurs on the outside of the non-presentational hint will do nothing (since the rule applied by the non-presentational hint overrides the default inheritance), and styling an element inside of it will always have an effect, even if the style is in a UA stylesheet. The rules for handling non-CSS presentational hints only act when CSS selectors match the HTML elements providing the presentational hints. For example, the following 2 statements are true because of the tree structure of the document:
<span style="color: green;"> <font color="red"> This text is red. </font> </span> <font color="red"> <span style="color: green"> This text is green. </span> </font>
An example of a situation that *is* affected by the rules for non-CSS presentational hints given in CSS2 is the following:
<font color="red" STYLE="color: green">
This text is green.
</font>
However, if the user stylesheet contained the rule
font { color: green; }
then what would happen is:
<font color="red">
This text is red.
</font>
because the non-presentational hint is treated as if it were a CSS rule at the beginning of the author stylesheet, and therefore overrides a rule in the user stylesheet.
Finally (and most importantly), how do the browsers handle this? Does
this actually mean anything? Surprisingly, the browsers handle it
quite well in its interaction with author stylesheets (interaction with
user stylesheets is not quite so good). I wrote a test for
this behavior, and MSIE 5 beta 2 passes the test perfectly.
Netscape 4.5 has a few bugs with PRE and with body
backgrounds, but handles the font face
examples fine. (I
tested font face
, not font color
.)
(Up to User Stylesheets Guide, CSS, David Baron)
LDB, dbaron@dbaron.org, 1999-06-15