Specificity

Three Numbers Decide Which Selector Wins

Specificity

Specificity is a three-part score — ids, classes/attributes/pseudos, and elements. Higher beats lower.

4 min read Level 2/5 #css#specificity#cascade
What you'll learn
  • Calculate specificity
  • Use `:where()` to keep specificity low
  • Avoid the specificity war

Specificity is a score CSS computes for each selector. When two rules target the same element, the one with the higher specificity wins.

The Score — Three Slots

Think of specificity as a three-digit number (A, B, C):

  • A — number of #id selectors
  • B — number of .class, [attribute], :pseudo-class selectors
  • C — number of element / pseudo-element selectors

Higher A beats any B. Higher B beats any C.

SelectorSpecificity
*(0, 0, 0)
p(0, 0, 1)
p.lead(0, 1, 1)
.card.featured(0, 2, 0)
nav a:hover(0, 1, 2)
#nav a(1, 0, 1)
Inline style="..."(1, 0, 0, 0) — beats all selectors
!importantoverrides specificity entirely

Quick Examples

p              { color: black; }   /* (0, 0, 1) */
.lead          { color: gray; }    /* (0, 1, 0) — wins */
#hero p        { color: red; }     /* (1, 0, 1) — wins over both */

For a <p class="lead"> inside <div id="hero">, the text is red.

The Specificity War

The classic bad spiral:

.btn { background: blue; }                 /* (0, 1, 0) */
.card .btn { background: green; }          /* (0, 2, 0) — wins */
.sidebar .card .btn { background: pink; }  /* (0, 3, 0) — wins */

Each rule “fixes” the previous by being more specific. Soon nothing can be overridden without !important or ever-deeper nesting.

The fix:

  • Keep selectors flat (one class is usually enough)
  • Use modifier classes (.btn--primary, .btn--danger) instead of nesting
  • Use cascade layers (@layer) to put high-specificity author rules over low-specificity defaults

:where() — Zero Specificity

:where() matches like its argument but contributes zero specificity:

:where(.card, .panel) p { color: gray; }

A later, simpler .lead { color: red; } overrides it without needing to be more specific. Great for low-priority defaults.

:is() — Same Specificity as the Highest Inner

:is(.card, .panel) IS specific — it picks the specificity of its most specific argument. Use it for grouping; use :where() for suppressing.

Up Next

Inheritance — when no rule matches, what happens.

Inheritance →