CSS Specificity & The Cascade
Understanding specificity is essential for debugging CSS. When two rules target the same element, specificity determines which one wins. Master the specificity hierarchy, avoid !important, and write CSS that's easy to override and maintain.
Specificity Hierarchy
- 1. !important — Highest priority (avoid!). Overrides everything. Only use for utility classes
- 2. Inline styles — style='color: red'. Specificity: 1,0,0,0. Avoid in production
- 3. ID selectors — #header. Specificity: 0,1,0,0. Each ID adds 100 to specificity
- 4. Class / attribute / pseudo-class — .card, [type='text'], :hover. Each adds 10
- 5. Element / pseudo-element — div, p, ::before. Each adds 1
- 6. Universal selector — *. Specificity: 0,0,0,0. No weight
- Combining — .card .card__title = 0,0,2,0 (two classes). div.card = 0,0,1,1 (one class + one element)
Specificity Code
/* Specificity examples (lower → higher) */
/* Specificity: 0,0,0,1 */
p { color: blue; }
/* Specificity: 0,0,1,0 */
.text { color: green; } /* WINS over p */
/* Specificity: 0,0,1,1 */
p.text { color: red; } /* WINS over .text */
/* Specificity: 0,1,0,0 */
#main { color: purple; } /* WINS over p.text */
/* ❌ BAD: Specificity wars */
#header .nav .nav-item a.active { color: red; } /* 0,1,3,1 — very hard to override! */
/* ✅ GOOD: Flat specificity with BEM */
.nav__link--active { color: red; } /* 0,0,1,0 — easy to override! */
/* ❌ BAD: Using !important to win specificity wars */
a { color: blue !important; } /* Now NOTHING can override this easily */
/* ✅ GOOD: Fix the root cause instead */
.nav__link { color: blue; } /* Low specificity, easily overridable */
/* Use @layer for specificity control */
@layer components { .btn { color: blue; } }
@layer utilities { .text-red { color: red; } } /* Wins! (later layer) */Tip
The goal: every selector should be one class = specificity 0,0,1,0. If you achieve this with BEM, every style is equally overridable. No specificity wars, no !important, no nested selectors. This is the gold standard of CSS architecture.
Higher specificity wins when multiple rules target the same element
Common Mistake
Using IDs (#header) in CSS selectors. One ID has 100x the specificity of a class. #header .nav a is nearly impossible to override without !important. Use classes exclusively in CSS — save IDs for JavaScript and anchor links.
Practice Task
Audit your CSS specificity: (1) Search for any # selectors and replace with classes, (2) Flatten any nested selectors deeper than 2 levels, (3) Remove all !important declarations and fix the root cause, (4) Verify every selector is 0,0,1,0.
Quick Quiz
Key Takeaways
- Understanding specificity is essential for debugging CSS.
- 1. !important — Highest priority (avoid!). Overrides everything. Only use for utility classes
- 2. Inline styles — style='color: red'. Specificity: 1,0,0,0. Avoid in production
- 3. ID selectors — #header. Specificity: 0,1,0,0. Each ID adds 100 to specificity