stackademic

The leading education platform for anyone with an interest in software development.

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 !important instead 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 style attributes 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