Inheritance & Cascade

Difficulty: Beginner

The 'C' in CSS stands for 'Cascading,' and understanding the cascade is arguably the most important concept in CSS. The cascade is the algorithm that determines which CSS declarations are applied when multiple rules target the same element with conflicting property values. It considers three main factors in order: importance and origin, specificity, and source order.

The cascade resolves conflicts by first checking importance. Declarations marked with !important override all normal declarations. Among normal declarations, styles from the author (your CSS) take precedence over user styles (user-defined browser settings) which take precedence over browser defaults (user-agent stylesheet). Within the same importance level, the cascade uses specificity to determine the winner. If specificity is also equal, the last rule in source order wins. This layered resolution is why CSS works the way it does.

Specificity is a scoring system that determines which selector 'wins' when multiple selectors target the same element. It is calculated as a tuple of four values: inline styles count (thousands), ID selectors (hundreds), class/attribute/pseudo-class selectors (tens), and element/pseudo-element selectors (ones). For example, #header .nav a has specificity (0, 1, 1, 1) - one ID, one class, one element. A selector with higher specificity always wins regardless of source order. Inline styles (style="") have the highest specificity short of !important.

Inheritance is a separate mechanism from the cascade. Certain CSS properties, when applied to a parent element, are automatically passed down to all descendants. Inherited properties are typically text-related: color, font-family, font-size, line-height, text-align, visibility, cursor, and others. Non-inherited properties include most box model and layout properties: width, height, margin, padding, border, display, position, background. You can force inheritance with the inherit keyword (border: inherit) or reset to initial values with the initial keyword.

The !important declaration should be used sparingly. It overrides all other declarations regardless of specificity, which makes debugging CSS much harder. The only way to override an !important rule is with another !important rule of equal or higher specificity. Overuse of !important leads to specificity wars where developers keep escalating to override each other's styles. Legitimate uses include utility classes (like .hidden { display: none !important; }) and overriding third-party library styles. In general, if you need !important, it often means your selector strategy needs restructuring.

Code examples

The Cascade in Action

/* Browser default (user-agent): color is black */

/* Author stylesheet: */
p {
  color: gray;          /* Specificity: 0,0,0,1 */
}

.intro {
  color: blue;          /* Specificity: 0,0,1,0 - wins over p */
}

#welcome {
  color: green;         /* Specificity: 0,1,0,0 - wins over .intro */
}

/* Source order: later rules win at equal specificity */
.text { color: red; }
.text { color: purple; }  /* purple wins - same specificity, later in source */

/* !important overrides everything */
.override {
  color: orange !important;  /* Wins over all normal declarations */
}

The cascade resolves conflicts: 1) !important beats everything, 2) Higher specificity beats lower, 3) Later source order beats earlier (at equal specificity). This is how CSS determines which styles apply.

Inheritance

/* Properties that inherit: */
body {
  color: #333;            /* Inherited by ALL descendants */
  font-family: Arial, sans-serif;  /* Inherited */
  font-size: 16px;        /* Inherited */
  line-height: 1.6;       /* Inherited */
}

/* All text inside body is now gray, Arial, 16px */
/* You only need to override where different: */
h1 {
  font-size: 2rem;        /* Override inherited font-size */
  color: #111;            /* Override inherited color */
}

/* Properties that do NOT inherit: */
.parent {
  border: 2px solid red;  /* NOT inherited by children */
  padding: 20px;          /* NOT inherited */
  margin: 16px;           /* NOT inherited */
  background: #f0f0f0;    /* NOT inherited */
}

/* Force inheritance or reset: */
.child {
  border: inherit;        /* Explicitly inherit border from parent */
  color: initial;         /* Reset to browser default (black) */
  margin: unset;          /* Inherit if inheritable, else initial */
}

Text-related properties (color, font, line-height) inherit automatically from parent to child. Box model properties (margin, padding, border, background) do not. Use inherit, initial, or unset keywords to control this behavior.

Specificity Calculation

/* Specificity format: (inline, IDs, classes, elements) */

p { }                          /* 0,0,0,1 */
.card { }                      /* 0,0,1,0 */
#header { }                    /* 0,1,0,0 */
p.intro { }                    /* 0,0,1,1 */
div p.intro { }                /* 0,0,1,2 */
#header .nav a { }             /* 0,1,1,1 */
#header .nav a.active { }      /* 0,1,2,1 */

/* Inline styles (highest without !important) */
/* <p style="color: red;"> */  /* 1,0,0,0 */

/* Practical example: which color wins? */
.card .title { color: blue; }      /* 0,0,2,0 */
div.card h2.title { color: red; }  /* 0,0,2,2 */
/* Red wins: 0,0,2,2 > 0,0,2,0 */

#main .title { color: green; }     /* 0,1,1,0 */
/* Green wins over both: ID selector beats classes */

Specificity is calculated as a tuple. IDs (0,1,0,0) always beat classes (0,0,1,0) regardless of how many classes you chain. The universal selector (*) and combinators (+, >, ~) add zero specificity.

Avoiding !important

/* BAD: Specificity war with !important */
.button {
  background: blue !important;
}
.button.danger {
  background: red !important;  /* Need !important to override */
}
.button.danger.confirmed {
  background: darkred !important;  /* Escalating... */
}

/* GOOD: Use proper specificity instead */
.button {
  background: blue;
}
.button.danger {
  background: red;       /* Higher specificity, no !important needed */
}
.button.danger.confirmed {
  background: darkred;   /* Even higher specificity */
}

/* Acceptable uses of !important: */
.visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
}

Avoid !important by using proper selector specificity. Chaining classes increases specificity naturally. Reserve !important for utility classes and overriding third-party styles.

Key points

Concepts covered

Cascade, Specificity, Inheritance, !important, Source Order, Initial Values, Computed Values