How to use the specificity calculator
- Paste selectors: one per line, or a comma-separated list (each selector is calculated separately).
- Turn sorting on to rank them from strongest to weakest.
- Read the breakdown: each counting part is shown with its own contribution.
- Export text, CSV or JSON.
Reading the result
(1,2,1) for #nav .item a:hover means one ID, two class-level parts (.item and :hover) and one element (a). Compare from the left: (0,10,0) still loses to (1,0,0).
How it works
Specificity is counted as three numbers (a, b, c). a counts ID selectors; b counts classes, attribute selectors and pseudo-classes; c counts type selectors and pseudo-elements. The universal selector and combinators count as zero. :is(), :not() and :has() take the specificity of their most specific argument, :where() always counts as zero, and :nth-child(… of S) adds the specificity of S. Two selectors are compared a first, then b, then c.
Worked examples
Example 1: why won’t my style apply?
Load Overrides. .btn is (0,1,0), body .btn is (0,1,1), and #app .btn is (1,1,0). If a library uses #app .btn, your .btn rule can’t win without an ID or a hack. Doubling a class (.btn.btn) raises specificity without IDs.
Example 2: low-specificity defaults
Load :is() vs :where(). :where(#hero, .banner) .title counts only .title (0,1,0), so any normal class can override it. That makes :where() perfect for resets and component libraries.
Example 3: framework selectors
Load Framework. Navigation selectors from popular frameworks often reach (0,4,0) or more, which explains why overriding them takes long selectors. Cascade layers are a cleaner solution.
Keeping specificity low
- Prefer single classes (BEM, utilities) over long chains.
- Avoid IDs in stylesheets; use them for links and JavaScript.
- Use
:where()for defaults and@layerto order groups of styles. - Reserve
!importantfor utilities that must always win.
Common mistakes
- Counting combinators.
>,+,~and spaces add nothing. - Treating
:not()as zero. It counts its most specific argument. - Forgetting pseudo-elements.
::beforecounts like an element.
Debugging a cascade problem
When a style doesn’t apply, open your browser’s developer tools and inspect the element. Crossed-out declarations show which rule lost. Paste both selectors here to compare them, and check whether a cascade layer, an !important or an inline style is involved before raising specificity yourself. Often the cleanest fix is lowering the other selector’s specificity, for example by wrapping it in :where() or moving it into an earlier cascade layer, rather than escalating your own.