How to use the CSS specificity calculator
- Paste selectors into Selectors, one per line. A line with commas is split into separate selectors.
- Read the Highest line for the strongest selector in your list.
- Use the table: Specificity (a,b,c) gives the score and How it adds up lists each part with its own score.
- Fix any row marked invalid; its message says what went wrong and where.
What it does and when to use it
When two rules set the same property on the same element, the browser uses the one with higher specificity, and only falls back to source order when the scores tie. Most “why is my CSS not applying?” moments come down to this. Paste the selector you wrote and the one that is winning, and the table shows exactly which part tips the balance.
It is also useful when planning a stylesheet: you can check that utility classes score low enough to be overridden, or that :where() really removes the weight of a reset. To tidy the stylesheet afterwards, run it through the CSS minifier, and keep shared values in custom properties with the CSS variables generator so fewer overrides are needed. For a full component, the CSS button generator writes low, single-class selectors.
How it works
The calculator reads each selector from left to right. #id adds 1 to a; .class, [attribute] and pseudo-classes such as :hover add 1 to b; element names and pseudo-elements such as ::before add 1 to c. The old single-colon forms :before and :after count as pseudo-elements. Combinators (>, +, ~, space) and * add nothing. :nth-child(2 of .item) counts as one pseudo-class plus its of selector. Results are sorted to find the highest.
MDN lists :is() and :where() as Baseline widely available since January 2021 and :has() since December 2023.
Worked examples
The sample list. The default selectors give
Highest: #nav .menu > li a:hover → (1, 2, 2). In the same list, :where(.card) h2 scores only 0,0,1.
Long chains lose to one class. a.nav-link[aria-current="page"] scores 0,2,1, while header nav ul li a scores 0,0,5. The short selector wins despite having fewer parts.
A modern and a broken selector. li:nth-child(2 of .item) scores 0,2,1. The typo .a..b is reported as invalid | Expected a class name after . at position 3.
Limits and tips
- The nesting selector
&counts as zero here, because its real weight depends on the parent rule. - Scores do not prove a rule applies. The selector must also match the element, and cascade layers and origin come before specificity.
- Lower is easier to maintain. If you keep raising specificity to win, consider
:where()for base styles instead.
Frequently asked questions
What do the three numbers mean?
Does 0,0,11 beat 0,1,0?
How are :is(), :not() and :has() counted?
What about inline styles and !important?
Why does a comma-separated selector show as several rows?
Sources
- Specificity - CSS | MDN — MDN Web Docs, accessed 2026-10-08
- :where() - CSS | MDN — MDN Web Docs, accessed 2026-10-08
How do we know nothing is uploaded? Test it yourself on the privacy proof page.