Skip to main content

CSS Specificity Calculator

Calculate the CSS specificity of one or more selectors as an (A, B, C) triple — ID, class/attribute/pseudo-class, and type/pseudo-element counts — to debug why a style rule isn't winning.

Input

Output

Specificity
SelectorIDClassTypeSpecificity
No data yet
Was this helpful?

Guides

What is CSS specificity?

When two CSS rules target the same element and set the same property, the browser needs a tiebreaker to decide which one wins. That tiebreaker is specificity — a score computed from the selector itself, not from where the rule appears in the stylesheet (that only matters as a final tiebreaker, when specificity is equal). A more specific selector always beats a less specific one, no matter which rule was written last.

The (A, B, C) system

Specificity is expressed as three numbers, compared left to right like a version number — any difference in A outweighs any difference in B, which outweighs any difference in C:

  • A — ID selectors. Each #id in the selector adds one.
  • B — classes, attributes, and pseudo-classes. Each .class, [attr], or :hover-style pseudo-class adds one.
  • C — types and pseudo-elements. Each tag name (div, a) and each pseudo-element (::before, ::after, and the legacy single-colon forms :before/:after/:first-line/:first-letter) adds one.

The universal selector (*) and combinators ( , >, +, ~) always contribute zero — they narrow what's matched, not how specific the match is. So #header scores (1, 0, 0), .nav a:hover scores (0, 2, 1) (two class-ish selectors, one type), and .btn.btn-primary — two classes on the same element — scores (0, 2, 0), beating a single-class rule even though it's the "same kind" of selector.

The :not() / :is() / :has() gotcha

Modern CSS scores :not(), :is(), and :has() by the specificity of their most specific argument, not as a flat pseudo-class. This calculator uses the simpler, pre-Selectors-4 approximation instead: each of these (and any other functional pseudo-class, like :nth-child()) counts as a single pseudo-class — a flat +1 to B, regardless of what's inside the parentheses. It's a documented scope cut, not a bug: it keeps the parser simple and is accurate for the common case (a single, unnested argument), but will undercount a :not() wrapping something with an ID inside it. :where() always scores zero, per spec, no matter its contents.

How to use it

Paste one CSS selector per line — as simple as .btn or as compound as #main .content > p::before:hover. Each line gets its own row with its ID, class, and type counts plus the combined (A, B, C) score. Results update as you type.

FAQ

Why does div > p::before outrank #main... or does it? It doesn't — an ID (A) always outweighs any number of type selectors or pseudo-elements (C), by definition of how the three numbers compare.

Does the order of rules matter if specificity is equal? Yes — when two rules have identical specificity, the one that appears later in the cascade (or was loaded later) wins. !important overrides specificity entirely, and inline style="" attributes outrank any selector-based rule.

Does this handle selector lists like .a, .b? Treat each comma-separated group as its own line for a per-selector breakdown — a selector list applies its rule to each selector independently, and each can have a different specificity.

Privacy

Parsing and scoring happen entirely in your browser. Selectors you paste in are never uploaded or stored.

cssspecificityselectorsweb-development

Love the tools? Lose the ads.

One payment clears every ad from your account, for good. No subscription, no tracking.