Skip to content
AZ Tools

CSS Specificity Calculator

Paste any CSS selector to see its (ID, class, type) specificity, per-token breakdown, and head-to-head comparison with another selector.

IDs

1

Classes / attrs / pseudo

2

Types / pseudo-el

3

Specificity
(1, 2, 3)

Token breakdown

  • #navID+(1, 0, 0)
  • ulType+(0, 0, 1)
  • liType+(0, 0, 1)
  • .activeClass+(0, 1, 0)
  • aType+(0, 0, 1)
  • :hoverPseudo-class+(0, 1, 0)

Compare two selectors

Paste a second selector to see which one wins the cascade.

Selector A

(1, 2, 3)

← A wins

Selector B

(0, 1, 3)

Examples

Inline styles, !important, and source order all beat selector specificity. This tool only computes the (ID, class, type) tuple from the selector itself.

How to use

  1. Type or paste any CSS selector — the breakdown updates as you type.
  2. Read the (ID, class, type) numbers — higher tuple wins the cascade.
  3. Paste a second selector in the compare box to see head-to-head which one wins.

About this tool

Show

When two CSS rules target the same element, the cascade picks the rule with higher specificity — counted as (ID, class/attr/pseudo-class, type/pseudo-element). This tool parses your selector, weights every part (#id +1·0·0, .class +0·1·0, div +0·0·1), then walks pseudo-classes like :is(), :not(), :has() (highest argument wins) and :where() (always 0). Drop in two selectors to see which one wins the cascade and by how much, so you can stop guessing why a rule isn't applying.

The three numbers are compared left to right, not added up, and that is the part most explanations skip. A single ID beats any number of classes, so #header outranks a selector carrying a hundred class names; the columns never carry. Thinking of specificity as a base-10 number works until someone writes eleven classes, and then it stops.

Specificity is also only the third tiebreak, not the first. An !important declaration wins over any normal one regardless of the selector, inline styles sit above normal author rules, and cascade layers are consulted before specificity is ever compared. When two declarations end up equal on all of that, the last one in source order wins. A rule that refuses to apply despite the higher score is usually losing on one of those earlier rounds rather than on this one.

:where() exists precisely to opt out of this arithmetic: it always contributes zero, which is what makes it the right tool for library defaults that authors should be able to override with a single class. :is() and :not() instead take the specificity of their most specific argument, so :is(h1, #title) is as heavy as #title even when it matches an h1.

The count describes the selector, not the match. Two selectors can score identically and still target different elements, and a higher score on paper means nothing if the rule never matches the element you are looking at.

Frequently asked questions

Why three numbers instead of one?

Specificity is compared column-by-column from left: one ID always beats any number of classes; one class always beats any number of type selectors. Adding them up like (0,1,0) + (0,0,10) = 20 is the classic wrong intuition the CSSWG warns against.

How are :is(), :not(), :has() counted?

They take the specificity of their highest-weight argument. :is(#a, .b) = 1·0·0, :not(.a, .b) = 0·1·0. :where() always contributes 0·0·0 — useful for zero-specificity overrides.

What about pseudo-elements like ::before?

Pseudo-elements (::before, ::after, ::first-line) count as type selectors (0·0·1). Legacy single-colon forms (:before, :after) are recognized as pseudo-elements too.

Does this include inline styles?

No — inline style is a separate 'a' bucket (1·0·0·0) that this tool doesn't model since you can't write inline styles in a selector. Add !important when you need to override inline styles.

Related tools