CSS Specificity Wars — Understanding Selector Precedence
Understand how CSS specificity determines which styles win. Learn to calculate specificity, resolve conflicts, and avoid the !important escape hatch with practical examples.
Detailed Explanation
CSS Specificity Wars
When multiple CSS rules target the same element, specificity determines which one wins. Understanding specificity is crucial for debugging styling issues and writing maintainable CSS.
The Specificity Hierarchy
Specificity is calculated as a three-part vector (a, b, c):
| Component | Weight | Examples |
|---|---|---|
| a — ID selectors | Highest | #header, #nav |
| b — Classes, attributes, pseudo-classes | Medium | .nav, [type], :hover |
| c — Elements, pseudo-elements | Lowest | div, ::before |
Calculating Examples
* → (0, 0, 0)
p → (0, 0, 1)
.intro → (0, 1, 0)
p.intro → (0, 1, 1)
#header → (1, 0, 0)
#header .nav li → (1, 1, 1)
#header .nav li.active a:hover
→ (1, 3, 2)
Resolution Rules
- Higher specificity always wins, regardless of source order
- Equal specificity? Last rule in source order wins
- Inline styles (
style="") beat all selectors !importantbeats everything (including inline styles)
Avoiding Specificity Problems
- Do: Use flat, class-based selectors (
.nav-itemnot#nav > ul > li) - Do: Use BEM naming (
.block__element--modifier) - Don’t: Nest selectors more than 3 levels deep
- Don’t: Use IDs for styling
- Don’t: Use
!important(except for utility classes)
CSS Layers (@layer)
CSS Cascade Layers provide a new way to manage specificity:
@layer base, components, utilities;
@layer base { p { color: black; } }
@layer components { .text-red { color: red; } }
@layer utilities { .text-blue { color: blue; } }
Layers defined later override earlier ones, regardless of selector specificity within each layer.
Use Case
Understanding specificity is essential for every front-end developer. It explains why styles sometimes don't apply as expected, why overriding third-party CSS can be difficult, and why CSS architectures like BEM exist. Specificity debugging is a daily task in large codebases, component library development, and when integrating multiple CSS sources (frameworks, themes, custom styles).