The Cascade, Specificity & Inheritance
When two rules disagree, the cascade picks a winner using origin, specificity, and source order.
Three layers of conflict resolution
CSS properties are declarations, and multiple declarations can target the same element. The **cascade** is the algorithm that decides which one wins. It applies three criteria in order: **origin and importance**, then **specificity**, then **source order**.
**Inheritance** is separate but related: some CSS properties flow down the DOM tree by default (like color and font-size), so child elements can pick up values from their ancestors without being explicitly targeted.
Predictable styles require understanding all three
Specificity is the most common source of 'why is my style not applying?' bugs. The fix is rarely !important; it is usually writing a more specific selector or restructuring the stylesheet order.
Understanding inheritance tells you which properties you can set once on a parent (<body>) and rely on children to pick up, versus which you must repeat on every targeted element.
How each layer works
**Origin:** The browser has its own default stylesheet (User Agent). Author styles (your CSS) override UA styles. !important reverses this: !important author beats !important user, but should be a last resort because it breaks the normal cascade.
**Specificity:** Each selector earns a score. Inline style= = (1,0,0,0). An id #x = (0,1,0,0). A class .x, attribute [x], or pseudo-class :hover = (0,0,1,0). A type div or pseudo-element ::after = (0,0,0,1). Universal * and combinators contribute 0. Add up all the scores; higher tuple wins. You cannot 'overflow' from type to class: ten classes (0,0,10,0) still lose to one id (0,1,0,0).
**Source order:** When origin and specificity are equal, the declaration that appears later in the stylesheet wins. This is why a <style> block placed after a <link> can override it.
**Inheritance:** Properties like color, font-family, font-size, line-height, text-align inherit by default. Layout properties like margin, padding, background, border, width do not. Use inherit to force inheritance, initial to reset to the CSS spec default, or unset to get the natural default (inherit if inheritable, else initial).
Try it
Watch the specificity scoreboard light up, see conflicting rules resolved, and observe which properties inherit down the tree.
Specificity scoreboard
| Selector | Inline | ID | Cls | Type | Note |
|---|---|---|---|---|---|
| p | 0 | 0 | 0 | 1 | type selector |
| .card:hover | 0 | 0 | 2 | 0 | class + pseudo-class |
| #hero .titlewinner | 0 | 1 | 1 | 0 | id + class |
Specificity is compared column by column, left to right. The first column that differs decides the winner.
Cascade conflict resolution
.card p { color: #34d399; }
Specificity: (0,0,1,1)
p { color: #94a3b8; }
Specificity: (0,0,0,1)lost: lower specificity
The <p> inside .card renders in emerald. Higher specificity wins.
Inheritance: what flows down the tree?
Parent element (styles set here)
Text-related properties (`color`, `font-*`, `line-height`) inherit. Box-model properties (`margin`, `padding`, `background`, `border`) do not. Use inherit to force any property to inherit.
Check yourself
Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.
Remember this
- Cascade order: origin/importance first, then specificity, then source order.
- Specificity tuple: (inline, id, class/attr/pseudo-class, type/pseudo-element). Higher = wins.
- Properties like
colorandfont-sizeinherit by default. Layout props likemargindo not. - Use
inherit,initial,unsetto control inheritance explicitly. Avoid!importantexcept as a last resort.
Done with this concept?
Mark it complete to track your progress. No login needed.