DAN STORM

skip to main content skip to secondary navigation

CSS Tutorial

The Cascade

A UA must have a mechanism to correctly apply styles when conflicts arise due to competing declarations. The W3C says,

Find all declarations that apply to the element and property in question, for the target media type. Declarations apply if the associated selector matches the element in question. Sort according to importance (normal or important) and origin (author, user, or user agent). In ascending order of precedence:

  • user agent declarations
  • user normal declarations
  • author normal declarations
  • author important declarations
  • user important declarations

Sort rules with the same importance and origin by specificity of selector: more specific selectors will override more general ones. Pseudo-elements and pseudo-classes are counted as normal elements and classes, respectively.

Finally, sort by order specified: if two declarations have the same weight, origin and specificity, the latter specified wins. Declarations in imported style sheets are considered to be before any declarations in the style sheet itself.

It is unclear what "weight" refers to in the last paragraph. It would seem that weight refers both to origin and specificity, that is, to the outcome of all the calculations described, rather than being one factor in calculating the outcome. At any rate, we can put this in plainer English by saying that five factors go into determining the application of styles.

  • weight in terms of specificity of competing declarations
  • weight in terms of proximity of declarations to an element, that is, whether a style is inline, embedded, linked, or imported, as well as its location within an embedded, linked, or imported file
  • weight in terms of origin, that is, user style sheets versus author style sheets versus UA style sheets (default rendering of the UA)
  • weight in terms of important rules
  • rules of inheritance

A style can be assigned to a P element in several different author style sheets, or in several places within an author style sheet, whether linked, imported, or embedded. A style can also be applied inline. UAs also have built-in styling for HTML elements. For example, there is default vertical spacing before and after a P element depending upon the UA, just as there is indentation for a BLOCKQUOTE element, and generally a default background color, whether gray or white associated with the BODY element. Moreover, a user may have personal settings in a user style sheet, sometimes related to a disability. Important declarations and inheritance further determine how styles are applied. We will now examine each of these five aspects of the cascade more closely.

Weight

Weight increases both with specificity and proximity to the target element.

Specificity

Specificity refers to the relative weight of a style declaration based on its type and complexity. For example, class and ID selectors are more specific than a single HTML element selector, and thus have more weight. Selectors using combinators are more specific than a single element selector, which in turn has more weight than the universal selector. When there are two compound selectors, the one with more elements is more specific than the one with fewer. (Pseudo-elements and pseudo-classes are counted as normal elements and classes respectively.) In the next example each declaration is more specific than the previous one.

* {color: black;} p {color: green;} div p {color: blue;} p.abc {color: red;} div p.abc {color: yellow;} div#header p {color: purple;} div#header p.abc {color: orange;}
Proximity

Proximity refers to the relative weight of a declaration based on its nearness or distance from the affected element. CSS declarations can be inline, embedded, linked, or imported, which translates from high to low specificity. Proximity is also calculated for competing styles within the same embedded, linked, or imported style sheet. You may recall the example above with the blue and yellow classes, which occur together within the same CSS file or style block.

CSS: .blue {color: blue;} .yellow {color: yellow;} HTML: <p class="yellow blue">Some text</p>

The "yellow" class will prevail since it has greater proximity to the affected element, as it comes later in the same embedded, linked, or imported style sheet. In the following example this declaration is in a linked style sheet.

div#one div#two {color: red;}

And this declaration is in an embedded style sheet, that is, within <style> tags.

div#one div#two {color: blue;}

The latter declaration has greater proximity, and thus the element will be rendered blue. The opposite would be true if the latter declaration were instead in a style sheet imported into the linked style sheet. But how is weight calculated when specificity and proximity both come into play? In the following example the text will be blue. Although the second declaration has greater proximity to the element, the former declaration has greater specificity.

CSS: div#one div#two p {color: blue;} div#one div#two {color: red;} HTML: <div id="one"> <div id="two"> <p>What color is this text?</p> </div> </div>

In the following example proximity will have greater weight than specificity because it is an inline declaration. The text will be red.

CSS: div#one div#two p {color: blue;} HTML: <div id="one"> <div id="two"> <p style="color: red">What color is this text?</p> </div> </div>

Nevertheless, in the following example greater specificity wins out because of the important rule. The text will be blue.

CSS: div#one div#two p {color: blue !important;} HTML: <div id="one"> <div id="two"> <p style="color: red">What color is this text?</p> </div> </div>

The W3C has a formula to calculate specificity.

  • count 1 if the selector is a 'style' attribute rather than a selector, 0 otherwise (= a) (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
  • count the number of ID attributes in the selector (= b)
  • count the number of other attributes and pseudo-classes in the selector (= c)
  • count the number of element names and pseudo-elements in the selector (= d)
  • The specificity is based only on the form of the selector. In particular, a selector of the form "[id=p33]" is counted as an attribute selector (a=0, b=0, c=1, d=0), even if the id attribute is defined as an "ID" in the source document's DTD.
  • Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.
Some examples: * {} /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */ li {} /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */ li:first-line {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */ ul li {} /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */ ul ol+li {} /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */ h1 + *[rel=up]{} /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */ ul ol li.red {} /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */ li.red.level {} /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */ #x34y {} /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */ style="" /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */ <HEAD> <STYLE type="text/css"> #x97z { color: red } </STYLE> </HEAD> <BODY> <P ID=x97z style="color: green"> </BODY>

In the above example, the color of the P element would be green. The declaration in the "style" attribute will override the one in the STYLE element. From a practical standpoint, testing across browsers will determine weight.

Style Sheet Origin

A user can have a personal style sheet that overrides the author style sheet. This user style sheet is typically used to override colors or text size, perhaps to make text extra large or swap high contrast colors for the default. Furthermore, the user style sheet may contain important declarations too, which will override author important rules. (See below on important declarations). This is a change from CSS1. In CSS1, author important rules took precedence over user important rules. Per the W3C quote above, style sheet origins are weighted as follows, with each source below overriding the previous one.

  • user agent declarations, that is, styles built into the UA, such as a white background and black text of a certain size, etc.
  • user normal declarations, that is, styles or preferences that a user style sheet contains
  • author normal declarations, that is, styles that the UA encounters at the author's site
  • author important declarations, that is, important declarations that the UA encounters at the author's site
  • user important declarations, that is, important styles or preferences that a user style sheet contains meant to override all competing declarations

Practically speaking, we don't need to concern ourselves with user declarations, whether normal or important, because we cannot control them, nor should we. An argument can be made that a webpage belongs to the user once it is downloaded, in that they are free to resize the UA, change font size, contrast, and so forth. Though we love our beautiful designs, and clients want to ensure the integrity of their branding, the truth is no one has a right to take over someone's UA, including opening new instances of the browser. We cannot test for user declarations anyhow. On the other hand, we can override default UA settings by explicitly overriding default styling as we saw above under "Structuring CSS". This is perfectly legitimate since these styles are only a default so far as the user is concerned.

Important Rules

Important rules can be used to increase the specificity of a declaration. "!important" is actually comprised of two unique keywords, "!" and "important". The "!" should not be confused with the "not" operator. Together, the two keywords mean "important". They do not mean "not important". (But though they are two keywords, it is easier to refer to them together as the important rule.)

p {font: 12px sans-serif !important;}

The important rule increases the weight of a declaration so that it will trump any declaration that would otherwise have more weight, unless an otherwise weightier declaration also is set to important. In the following example the former declaration has greater weight than the latter, even though the latter is otherwise more specific and has—for the sake of our illustration—greater proximity to the targeted element.

p {color: black !important;} div#header > p.abc {color: red;}

The important rule will have this effect even if it is remote from the affected element, say, in an imported style sheet and the affected element has an inline style. Again, the only way to override the former declaration would be to use the important rule in the latter declaration. However, this is not a good idea. Use of the important rule should be strictly limited. If you declare a shorthand property to be important (e.g. font, background, border, etc.) the important rules apply to all the properties underlying the shorthand declaration.

Inheritance

Inheritance is not directly related to weight, but refers to styles that are indirectly or implicitly applied to descendants (without being declared). Certain elements inherit values from their parents. If an EM element, for example, appears within a P element, that EM element will inherit the P element's font-size, even though we did not assign that value to the EM element. This is a good thing. Because of this we do not need to specify styles for every element. Barring browser deficiencies, there is no need to reset the style for each descendant element that inherits those values. You can always override the inheritance, however, by assigning a property to a descendant element.

CSS2.1 introduced the property value "inherit". If a property does not normally inherit an ancestor value, then you can use the "inherit" value to assign that value to the descendant. If the property normally does inherit a value, using the inherit value will strengthen it in the cascade.

CSS: p {color: red} HTML: <p>Here is some text with one word <em>emphasized</em>.</p>

In the previous example, the text in the EM element will be red like the rest of the paragraph, assuming that it has not been otherwise defined. In this next example, the emphasized text will be blue because we have explicitly defined it to be blue.

CSS: p {color: red} em {color: blue;} HTML: <p>Here is some text with one word <em>emphasized</em>.</p>

However, in the next example, the emphasized text will be red because in the third line we are overriding the simple selector declaration. We are forcing the EM element to inherit the P element's color, rather than apply the default color defined for the EM in the previous line. This is scalable in that you may want an EM to inherit the color of a variety of elements, but retain its own color within other elements.

CSS: p {color: red} em {color: blue} p em {color: inherit} HTML: <p>Here is some text with one word <em>emphasized</em>.</p>

The appendix lists each property value, and indicates whether it is inherited or not, and whether the property has an inherit value. But here is a short list of properties that inherit.

  • color
  • font (and related properties)
  • letter-spacing
  • line-height
  • list-style (and related properties)
  • text-align
  • text-indent
  • text-transform
  • white-space
  • word-spacing

The Cascade

The CascadeThe cascade refers to the ripple effect of all declared styles, including the weight of user versus author declarations, as well as the inherent display of the UA. The origin of a declaration (that is, its weight in terms of its proximity to the element) and its specificity determine style application. Generally, author style sheets override user style sheets which override the UA style sheet. An exception takes place with the important declaration, which we examined above. Users with accessibility issues may, for example, set their font size to 300%. All things being equal, rules in imported style sheets take a back seat to rules in linked style sheets. Let's look at the cascade more closely.

In the image to the right we assume that we have linked to a style sheet (4) that has the styles most pertinent to the page we are viewing. That style sheet imports another style sheet (5) that contains styles pertinent to the broader section of the site that we are navigating. That imported style sheet itself imports the core style sheet (6) that has styles pertinent to the entire site, but which are meant to be overridden where necessary. Let's also assume that a style is specified both inline (2) and in an embedded style sheet in the HTML head (3). Let us also assume that users have a style sheet of their own with "!important" declarations (1). This style sheet contains user preferences, often, but not necessarily, related to a disability. Lastly, we are cognizant that elements may have inherent styles (7) displayed according to the native rules of the UA.

Any style in the user style sheet with the important declaration will override the author declaration if they come into conflict (1). Barring a user specification, the inline style will be applied because it has the next greatest weight (2). If the inline style is not specified, the embedded style is used (3). Next in line are the linked CSS file (4), and then its own imported CSS (5), and then the imported core CSS file (6). Lastly, the styles inherent in a P element (such as top and bottom margin, line-height, etc.) apply (7). This last eventuality would occur only if you had not specified margins for a P element or one of its parents, and if the user's style sheet had no such preferences. Incidentally, if you use the CSS best practice of neutralizing default padding and margin of many (if not all) elements, then condition 7 will never arise unless the user turns off styles or if the style declarations cannot be located by the UA.

Specified, Computed, and Actual Values

After all the style declarations have been sorted through, the UA may not still be quite ready to display the styles, because further calculations might need to be made. Values are applied to properties by a threefold calculation. The specified value is that which comes out of the cascade. If there is no specified value that comes out of the cascade, then the property is inherited from an ancestor. If there is no inherited property, the default property of the element is used. Some values need to be computed, especially if they are relative. Lastly, the actual value might have to be approximated if the user agent is restricted in some way.

Here is an example. Let's suppose that in the CSS the BODY element is assigned a font-size of 10 points (specified value), and the P element is assigned a font-size value of 120%. Since the P element font-size is not specified as an exact value, it must therefore be calculated (computed value). This will result in a value of 12 points. All things being equal, the actual value will equal this computed value, unless the UA has some limitations. If, for example, the UA cannot display at 12 points, it will approximate that calculation, and may render at, say, 11 points (the actual value). The computed value from a parent element becomes both the specified value and the computed value of the child.