Selectors and specificity

The selector vocabulary — combinators, attributes, pseudo-classes — plus a reliable way to reason about specificity.

Core selectors

SelectorMatches
*Every element (universal)
.cardAny element with class 'card'
#headerThe element with that id
a:hoverAnchor while hovered (pseudo-class)
p::first-lineFirst line of a paragraph (pseudo-element)
[type='submit']Any element with that attribute value
/* AND: both classes on the same element */
.btn.primary { }

/* descendants vs direct children */
.nav a   { }  /* any depth inside .nav */
.nav > a { }  /* only one level down  */

/* siblings */
h2 + p { }  /* the paragraph right after an h2 */
h2 ~ p { }  /* every paragraph after an h2     */

Scoring specificity

Think of specificity as three counters — (inline, IDs, classes) then element count. Compare left to right; the first difference decides the winner.

SelectorScoreNotes
style='…'1-0-0-0Inline wins over everything except !important
#main .card a0-1-1-1One id, one class, one element
.card a.active0-0-2-1Two classes, one element
ul li a0-0-0-3Elements only — weakest
💡
:hover, :focus, [type='text'] and ::before each count in the class column. :not() does not add weight itself — its argument does.

Writing selectors that survive

  • Prefer a single class — flat specificity makes overrides predictable.
  • Keep selectors short; long descendant chains couple your CSS to your HTML structure.
  • Use :is() to group alternatives without inflating specificity.
  • Naming conventions (BEM, utility classes) exist mostly to keep specificity flat by construction.
/* flat and predictable */
.card { }
.card--featured { }

/* grouped with :is() */
:is(h1, h2, h3) { line-height: 1.2; }

FAQ

Why does .a .b beat .b?
Two classes outweigh one. Specificity is additive, so nesting quietly raises specificity — a common reason overrides mysteriously fail.
id or class for styling?
Use classes. An id selector carries heavy weight (0-1-0-0) that you will regret the first time you need to override it.

CSS: getting started The box model

Last refreshed 2026-09-17.