Specificity
How the cascade resolves conflicting rules using specificity scoring
Overview
When multiple rules target the same element, specificity decides which declaration wins. Specificity is scored as three components — IDs, classes/attributes/pseudo-classes, and element/pseudo-element selectors — compared left to right. Inline styles and !important sit above the normal cascade, so understanding this hierarchy is key to predictable styling.
Syntax / Usage
Each selector earns a score (a, b, c): a counts IDs, b counts classes, attribute selectors, and pseudo-classes, c counts type selectors and pseudo-elements. Higher components win regardless of source order; ties fall back to the last rule declared.
/* (0, 0, 1) */
p { color: gray; }
/* (0, 1, 1) — wins over the above */
p.intro { color: black; }
/* (1, 0, 0) — beats any number of classes */
#lede { color: navy; }
Examples
A more specific selector overrides an earlier one despite ordering:
.button { background: blue; } /* (0, 1, 0) */
.sidebar .button { background: red; } /* (0, 2, 0) wins */
Using :where() to add selectors with zero specificity, keeping overrides easy:
/* :where() contributes (0, 0, 0) */
:where(.card) a {
color: inherit;
}
/* A plain class still overrides the link above */
.card .link { color: teal; }
!important overrides normal declarations but should be a last resort:
.alert { color: black !important; }
Common Mistakes
- Reaching for
!importantinstead of fixing selector specificity, creating override wars - Assuming later rules always win — a lower-specificity later rule loses to an earlier higher one
- Overusing ID selectors, which are hard to override later
- Forgetting that inline
styleattributes outrank almost every stylesheet rule - Treating specificity components as a single number (they never carry over between columns)
See Also
selectors custom-properties box-model