Cascade & Specificity
How CSS decides the winner — origin, importance, layers, specificity, and order — in human terms.
- css
- cascade
- specificity
When two declarations target the same property on the same element, the cascade picks one. Specificity is a step in that fight — not the whole rulebook.
If your debugging strategy is “add classes until it works, then !important,” this is the reset button.
Order of battle (simplified, author styles)
- Cascade layers (
@layer) — later layers beat earlier ones for normal declarations - Specificity of the selector
- Source order — last tied rule wins
- Inline styles sit high on the specificity ladder
!importantflips a lot of origin/layer rules — treat it as a last resort
User-agent and user styles also participate; most app work is author CSS.
Specificity as a scoreboard
Rough tuple: (inline, IDs, classes/attributes/pseudo-classes, elements/pseudo-elements).
| Selector | Rough weight |
|---|---|
div |
elements |
.card |
one class |
.card.featured |
two classes |
#hero |
one ID |
button:hover |
class-ish + element |
.nav a { color: blue; } /* class + element */
a.nav-link { color: red; } /* same ballpark — later wins if equal */
:where() contributes zero specificity — great for base styles you want to override easily.
:is() takes the most specific argument inside it — easy footgun with IDs.
Layers beat selector wars
@layer reset, base, components, utilities;
@layer components {
.button { color: white; }
}
@layer utilities {
.text-accent { color: var(--accent); }
}
A utility in a later layer can win even with a lighter selector. That’s how design systems stay sane.
Inheritance ≠ cascade
- Cascade chooses among declarations for a property.
- Inheritance fills inheritable properties (
color,font-*, …) when nothing was declared.
margin does not inherit. color does. inherit / initial / unset / revert are the explicit controls.
Habits that age well
- Prefer boring class selectors
- Reach for layers before escalating specificity
- Avoid IDs in app CSS
- Reserve
!importantfor rare utilities or third-party overrides - Theme with custom properties instead of selector cage matches
Debug checklist (DevTools)
- Is the property applied at all?
- Which rule is struck through?
- Layer or
!importantinvolved? - Did a later file silently win?
Further reading
Related
Related guides
- CSS Specificity Deep DiveCount IDs, classes, and elements correctly — :is/:where/:not, inline styles, !important, and how layers change who actually wins.
- Accent Color and Form ControlsUse accent-color to theme native checkboxes, radios, ranges, and progress — what it paints, what it skips, and when to custom-style instead.
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.
- BEM Naming MethodologyBlock, Element, Modifier naming for CSS — how it limits specificity wars, what to name, and when utility or CSS modules beat strict BEM.
- blend-mode Basicsmix-blend-mode vs background-blend-mode — how pixels combine, isolation, and the stacking/readability traps in product UI.