CSS·5 min read·By the StackUtils Team

CSS Specificity Demystified: The Complete Reference

Ever wondered why your CSS rule isn't applying? The answer is almost always specificity. Learn the (a, b, c) scoring system, !important, and how to win specificity battles cleanly.

The CSS Cascade

When multiple CSS rules target the same element and set the same property, the browser must decide which value wins. This decision process is called the cascade, and it evaluates rules in the following order (highest priority last):

  1. Browser (user-agent) stylesheet — Default styles for HTML elements
  2. User stylesheet — Reader-mode and accessibility overrides
  3. Author stylesheet — Your CSS files, <style> tags, and inline styles
  4. Author !important
  5. User !important
  6. Browser !important

Within author styles at the same origin and cascade layer, specificity is what determines the winner. If specificity is tied, the last rule in source order wins.

Specificity Scoring: The (A, B, C) System

Specificity is represented as three numbers (A, B, C):

  • A (hundreds column) — Count of ID selectors (#id)
  • B (tens column) — Count of class selectors (.class), attribute selectors ([type]), and pseudo-classes (:hover)
  • C (units column) — Count of type selectors (div, p) and pseudo-elements (::before)

Specificity is compared column by column, left to right. A selector with A=1 always beats a selector with A=0, regardless of how high B and C are. There is no overflow: even one hundred class selectors (B = 100) cannot override a single ID (A = 1).

Specificity of Every Selector Type

SelectorExampleSpecificity (A,B,C)
Universal selector*(0,0,0)
Type selectordiv, p, h1(0,0,1)
Pseudo-element::before, ::after(0,0,1)
Class selector.btn, .card(0,1,0)
Attribute selector[type='text'](0,1,0)
Pseudo-class:hover, :focus, :nth-child(2)(0,1,0)
ID selector#header, #nav(1,0,0)
Inline stylestyle="color: red"(highest, no A/B/C)
!importantcolor: red !importantOverrides all non-!important

Worked Examples

div p(0,0,2)Two type selectors
.nav a(0,1,1)One class + one type
ul li.active(0,1,2)One class + two types
#header .nav a:hover(1,2,1)One ID + two classes (class + pseudo-class) + one type
div#content > p.intro::first-line(1,1,3)One ID + one class + two types + one pseudo-element

!important: Power and Danger

Appending !important to a declaration makes it override all non-important declarations for that property on that element, regardless of specificity. It creates a separate “important” origin in the cascade.

The problem with !important:

  • It cannot be overridden by another rule in the same origin without adding another !important with higher specificity.
  • This leads to “specificity wars” where developers keep adding !important to overpower each other.
  • It makes code harder to maintain and debug.

Legitimate uses: overriding third-party library styles you cannot edit, and utility classes in design systems like Tailwind (e.g. !text-red-500 prefix syntax in Tailwind v3+).

Common Specificity Mistakes

  1. Over-qualifying selectors — Writing div.card p.text when .card .text suffices. Over-qualified selectors create unnecessary specificity that must be matched or beaten later.
  2. ID selectors for styling — IDs have such high specificity (1,0,0) that overriding them later requires another ID or !important. Prefer classes for styling.
  3. Inline styles — Inline styles are nearly impossible to override without !important. Keep styling in stylesheets.
  4. Not understanding :is() and :not() — The specificity of :is() and :not() is determined by their most specific argument, not the pseudo-class itself. :is(#id, .class) has specificity (1,0,0).

Best Practices for Manageable CSS

  • Keep specificity as low and flat as possible. Most selectors should be a single class.
  • Use BEM (Block Element Modifier) or similar methodologies to namespace classes and avoid deep selector chains.
  • Reserve IDs for JavaScript hooks, not CSS styling.
  • Use CSS layers (@layer, introduced in 2022) to manage specificity across libraries and feature areas without resorting to !important.
  • When debugging a styling issue, always check the DevTools Computed tab — it shows exactly which rule is applying and what is being overridden.

CSS tools for developers

Calculate specificity, generate gradients, and minify your CSS instantly.