The Cascade & Specificity
When several rules set the same property on the same element, only one value wins. The cascade is the algorithm that decides which, based on origin, importance, layers, specificity and order. Understanding it ends the frustration of "why isn't my CSS working?".
Rule 1: later wins (when everything else is equal)
Between two rules with equal weight, the one that appears last in the CSS wins. This applies across files too: a stylesheet linked later overrides one linked earlier.
Rule 2: specificity beats order
Even though p comes last, more specific selectors win regardless of order.
Calculating specificity
Specificity is a score with three columns, compared from left to right:
| Column | Counts | Example |
|---|---|---|
| A — ids | #id | #nav → (1,0,0) |
| B — classes, attributes, pseudo-classes | .class, [type], :hover | .btn:hover → (0,2,0) |
| C — types, pseudo-elements | p, ::before | ul li a → (0,0,3) |
A single id (1,0,0) beats any number of classes (0,10,0), and one class beats any number of type selectors. The universal selector * and combinators add nothing.
| Selector | Specificity |
|---|---|
li | (0,0,1) |
ul li | (0,0,2) |
.item | (0,1,0) |
ul li.item:hover | (0,2,2) |
#menu .item | (1,1,0) |
Browser developer tools show each selector's specificity when you hover it in the Styles panel.
Inline styles and !important
Inline style attributes beat any selector. !important on a declaration beats everything that isn't also important. It's an escape hatch, but it creates a war of escalating overrides — the only way to beat !important is another !important with higher specificity. Reserve it for utilities that must always win and for overriding third-party CSS you can't edit.
The full cascade order
From lowest to highest priority, the browser considers:
- Origin — browser defaults, then user settings, then author (your) styles.
- Cascade layers — styles in later
@layers beat earlier layers; unlayered styles beat layered ones (lesson 45). - Specificity — as above.
- Order of appearance — the last one wins.
!important reverses the origin and layer order, which is how users' accessibility settings can override sites.
Keeping specificity low
Most CSS problems come from specificity creeping upward. Habits that prevent it:
- Style with single classes; avoid ids in CSS.
- Avoid long descendant chains like
.page .sidebar ul li a. - Don't qualify classes with types (
div.card) unless necessary. - Use
:where()for zero-specificity defaults that are easy to override (lesson 43). - Organise with cascade layers instead of fighting with
!important.
Debugging "my CSS isn't applied"
- Inspect the element and look at the Styles panel.
- Is your rule listed at all? If not, the selector doesn't match (typo, wrong class, stylesheet not loaded).
- Is it crossed out? A more specific or later rule is winning — the panel shows which.
- Is it crossed out with a warning icon? The value or property is invalid.
Try it yourself
Predict the colour of each button, then check. Change one selector to change the winner.