Cascading Order and Inheritance in CSS
38

Cascading Order and Inheritance in CSS

CSS styles can be specified in many ways, but they will all cascade into one style sheet in the end. Sometimes conflicts will arise between the style sheets that influence how styles are merged. The cascading priorities of CSS can be confusing, and could often lead to excessive use of the !important rule in frustration when dealing with large sites. This post is to clarify the cascading order of CSS.

The Cascading Order

Styles are read in three ways: browser default (blue links etc), style sheets (internal in the <head> or external via @import or <link>) and inline styles. Here is the simulated default priority order, where no.4 as most important:

  1. Browser default
  2. External style sheet
  3. Internal style sheet
  4. Inline style

If two rules have the same weight, the latter wins. Imported style sheets and internal style sheets actually carry the same weight, but since imported styles are considered to be before any rules in the style sheet itself, the latter will win (the internal). This is not the case if you f.ex have two <style> tags inside your <head>, where second one uses the @import rule to import an external style sheet. That could be considered invalid according to the specs: In CSS1, all ‘@import’ statements must occur at the start of a style sheet, before any declarations.

Also worth noting in this list, is that any inline style will carry the same weight as #id definitions inside the style sheet. But again, since the inline style attribute comes latter, it will win the battle.

Internal Priorities

Now, let’s make a general list of the internal priorities for CSS (3 has the highest priority):

  1. element
  2. .class
  3. #id

This is the default priority order. In addition to this, specificity will also count, f.ex ul li will override li. W3C has made a decent table over how you should calculate internal weight:

LI            {...}  /* a=0 b=0 c=1 -> specificity =   1 */
UL LI         {...}  /* a=0 b=0 c=2 -> specificity =   2 */
UL OL LI      {...}  /* a=0 b=0 c=3 -> specificity =   3 */
LI.red        {...}  /* a=0 b=1 c=1 -> specificity =  11 */
UL OL LI.red  {...}  /* a=0 b=1 c=3 -> specificity =  13 */
#list         {...}  /* a=1 b=0 c=0 -> specificity = 100 */
  • a represents the number of #id attributes in the selector
  • b represents the number of class attributes
  • c represents the number of tag names

Combining these into a number will give you the actual weight. This means that f.ex li#list will have the same weight as ul #list. This is probably one of the most confusing things about the cascade, but it’s actually simpler than you might think: it’s all about counting.

!important

The !important rule is the way to override all of this. Putting !important after the declaration, but before the semicolon will simply override all previous cascade and give it the highest priority. If !important is specified more than once for the same element, they will fall back to the normal cascading rules. Also, declaring a shorthand property to be !important is equivalent to declaring all of its sub-properties to be !important.

Inheritance

Many web designers who are new to CSS often get confused by inheritance and how it works. During the cascade, property values are resolved to computed values. Some of these values are inherited from its parent’s element in the document tree. The very basic principle of inheritance is that properties with the value “inherit” will inherit its parent’s value for the same property into a computed value. Here’s a basic example:

red text

<p style="color: red; border: 1px solid #000;"><q><span>red text</span></q></p>

The property “color” with the value “red” will be inherited into the <q> and <span> elements, because it has the value “inherit” as default. The “border” property does not have inherit as default value, so only the paragraph will have a border, not its children. This is the most straightforward inheritance. Here is another more complex example, where a computed value will be calculated when inheritance occurs:

big text

<p style="font-size: 10px;"><span style="font-size: 200%;">big text</span></p>

The property “font-size” with the value “10px” will be inherited into the <span> element. The span takes this value and sums up its property “font-size” by combining it with the inherited value. So the <span>’s property “font-size” will have the value 20px after the cascade.

Some screen properties already have “inherit” as a default value, forcing themselves on children in the document tree. Here’s the list:

  • border-collapse
  • border-spacing
  • caption-side
  • color
  • cursor
  • direction
  • empty-cells
  • font
  • font-family
  • font-stretch
  • font-size
  • font-size-adjust
  • font-style
  • font-variant
  • font-weight
  • letter-spacing
  • line-height
  • list-style
  • list-style-image
  • list-style-type
  • quotes
  • text-align
  • text-indent
  • text-transform
  • white-space
  • word-spacing

Note: When using the universal selector * in CSS, be careful not to include any of the properties above that naturally inherit. Doing so will ruin the inheritance flow in the document later on.

Examples

We set up some cascading examples here as a reference. Here is the sample HTML I used for the test:

<p class="pclass" id="pid"><span class="sclass" id="sid">text</span></p>

Here are some CSS scenarios that could reside inside the style sheet with results explained:

  1. span#sid { color: red; }
  2. #pid span { color: green; }

The text will be rendered green. Both styles carry the same weight (one id, one tag) but the green value is last defined.

  1. #pid #sid { color: red; }
  2. p.pclass span#sid.sclass { color: green; }

The text will be rendered red. The first definition has two id’s, (weight 200) and second has one id, two tag names and two class attributes (122).

  1. #pid { color: red !important; }
  2. span { color: green; }

The text will be rendered green. Even if the first definition is #id-specified with !important and colour will be inherited, targeting elements further down the document tree wins.

  1. #pid { color: blue; font-size: 10px; }
  2. #pid span { color: red !important;}
  3. p #sid { color: green; font-size: 150%; }

The text will be rendered red in 15px size. Both definitions carry the same weight as default, but red wins the colour battle for its !important rule. The span will inherit the #pid defined font-size: 10px; and combine it with it’s own 150%. The result will be 10×1.5=15px.

This ends this guide on Cascading Order and Inheritance in CSS. Now you are ready to create amazing websites using CSS3 and HMTL5.