AniUI Academy

The Cascade and Inheritance

How equal-specificity rules resolve by source order, which properties inherit down the document by default and which don't, and the inherit, initial and unset keywords.

8 min read

You now know how the browser picks a winner when two selectors have different specificity — the higher one wins, full stop, no matter where either rule sits in the file. This lesson covers the two things that fill in the rest of the picture: what happens when specificity is genuinely equal, and how a value can reach an element without any rule targeting that element directly at all.

The cascade: source order breaks ties

"Cascade" is the C in CSS, and it's the mechanism for resolving conflicts. You already know its first rule from last lesson: higher specificity always wins, regardless of order. Its second rule is what happens when specificity is a genuine tie:

p { color: blue; }
p { color: green; }

Both selectors are a lone type selector — identical specificity. The second rule is written later in the source, so it wins: the text is green. Move the color: green rule above color: blue in the file, and the result flips. Order only matters as a tie-breaker after specificity has already failed to produce a winner — a p { color: red; } written at the very end of the file still loses to a .message { color: blue; } written at the very top, because a class always outweighs a type selector regardless of position.

This is also why <link>ed stylesheets and <style> blocks that appear later in a document can override ones that appear earlier — the browser treats them as one continuous, ordered set of rules.

Inheritance: some properties flow down for free

Some CSS properties, when left unset on an element, take their value from the nearest ancestor that does set it, rather than falling back to a browser default. This is inheritance, and it's separate from the cascade — it's not about two rules conflicting, it's about a value travelling down the document tree with no rule targeting the child at all.

body { color: #222; font-family: system-ui, sans-serif; }
<body>
  <p>This text is #222 and system-ui, with no rule mentioning <p> at all.</p>
</body>

Every element inside <body> inherits color and font-family from it, because both properties are inheritable. Nothing on <p> itself set them — the value simply flowed down.

Properties that inherit by default: text and typography properties — color, font-family, font-size, font-weight and the rest of the font-* family, line-height, text-align, and the list-style-* properties.

Properties that do not inherit by default: box model properties — margin, padding, border, width, height — along with background and display.

That split isn't arbitrary. Text properties cascading down an entire document is almost always what you want — set a font and a base colour once on body, and every paragraph, list item and heading picks it up without you repeating yourself. A box's own spacing, on the other hand, is rarely something you want copied onto every descendant: if margin inherited by default, giving one <div> a 2rem margin would push margin onto every element nested inside it too, which is almost never the intent. Each box manages its own spacing; only text-level styling is expected to flow.

inherit, initial, and unset

Three keywords let you control this explicitly, as a value for any property:

.child {
  color: inherit;   /* explicitly take the parent's computed value */
  margin: initial;  /* reset to the property's own default, ignoring the parent entirely */
  border: unset;    /* act like inherit if the property normally inherits, otherwise like initial */
}
  • inherit forces a property to take its parent's computed value, even if that property doesn't normally inherit. Useful for something like border-color: inherit when you want a child's border to match its parent's text colour exactly.
  • initial resets a property to its specification-defined default, ignoring whatever the parent has. color: initial resets to the browser's base black-ish default, not the parent's colour.
  • unset is the pragmatic middle ground: it behaves like inherit on properties that inherit by default, and like initial on properties that don't. It's the closest thing to "forget every rule that touched this and go back to how it would behave naturally."

Shorthand properties, and their real gotcha

A shorthand property sets several longhand properties in one declaration. margin is the clearest example:

margin: 10px 20px;
/* equivalent to: */
margin-top: 10px;
margin-right: 20px;
margin-bottom: 10px;
margin-left: 20px;

Two values means top/bottom, then left/right. Four values go clockwise from the top: margin: 10px 20px 30px 40px is top, right, bottom, left.

The gotcha, and it's a real and common one: a shorthand resets every longhand it covers, even the ones you didn't mention.

.card {
  margin: 20px;         /* sets all four sides to 20px */
  margin-top: 40px;      /* only top is overridden — right/bottom/left stay 20px, fine */
}

That example is safe, because the shorthand comes first. This one isn't:

.card {
  margin-top: 40px;   /* intent: a bigger top margin */
  margin: 20px;         /* this resets margin-top back to 20px too — the line above is wiped out */
}

If margin: 20px appears after margin-top: 40px, it silently overwrites the top value back to 20px, because the shorthand sets all four sides unconditionally — it doesn't know or care that you'd already set one of them on purpose. This is one of the most common real-world sources of "I set this and it's being ignored" bugs, and the fix is either to reorder the declarations (shorthand first, specific override after) or to only use the longhand once you're overriding a single side.

Try it yourself

body sets color and font-family once, and every element below inherits them without a single extra rule. Watch what happens to the box model properties (background, border, padding) instead — none of those travel down, so each box states its own.

Try it yourself
Loading playground...

What to remember

  • When specificity is equal, the cascade falls back to source order — later wins. Specificity itself still always wins over order when the two differ.
  • Text properties (color, font-*, line-height, text-align, list-style-*) inherit by default; box model properties, background, and display do not.
  • inherit forces a parent's value, initial resets to the spec default, unset picks whichever of those two behaviours is natural for that property.
  • A shorthand like margin: 10px 20px resets every longhand it covers — order your shorthand and longhand declarations carefully, or a later shorthand will silently undo an earlier specific override.

Check yourself

4 questions · pass 3/4 to unlock The Box Model

up to 50
  1. 1.Two rules both target the same element with the same specificity and set conflicting values for the same property. Which one wins?

  2. 2.Which of these properties is inherited by default?

  3. 3.What does color: inherit do on an element whose parent has color: red?

  4. 4.Why does margin: 10px 20px; followed later by margin-top: 5px; still leave margin-right, bottom and left at the shorthand's values?

4 left to answer