What the CSS Specificity Calculator does
This specificity calculator works out the (IDs, classes, types) weight of any CSS selector using the rules in Selectors Level 4 - including the modern pseudo-classes :is(), :not(), :has() and :nth-child(... of S), and the zero-weight :where() - tells you which of two selectors wins, and ranks every selector in a pasted stylesheet from heaviest to lightest.
Each result lists the parts that were counted, so you can see why #nav a beats a selector with five classes, or why wrapping something in :where() makes it easy to override. Parsing happens in your browser; your CSS is not uploaded.
How to use it
- Type or paste selectors, one per line. A line can be a comma-separated list; each selector in it is scored separately.
- Put two selectors in the comparison boxes to see which wins when both match the same element.
- Optionally paste a whole stylesheet. Rules inside @media, @supports, @layer and @container are included, nested CSS is resolved, and @keyframes and @font-face blocks are skipped.
- Sort the stylesheet table by specificity, line or !important count to find the selectors that make overrides hard.
- Download the results as CSV or print them.
Reading the results
Specificity is three separate counts, compared left to right like a version number: any ID beats any number of classes, and any class beats any number of element types. (1, 0, 0) beats (0, 12, 0).
Selectors with an ID, and rules using !important, are the usual source of override battles; the stylesheet summary counts both.
When two selectors tie, the one that appears later in the stylesheet wins. Specificity is also only one step of the cascade: origin, !important, cascade layers and scoping are decided first.
Worked example: why #nav a beats .site-header .nav .item a:hover
#nav a has one ID and one type: (1, 0, 1).
.site-header .nav .item a:hover has three classes, one pseudo-class and one type: (0, 4, 1).
The first column is compared first: 1 against 0. The ID selector wins immediately, however many classes the other has. Replacing #nav with :where(#nav) would drop it to (0, 0, 1), and the class-based selector would then win.
Formulas and scoring rules
- Counting
a = ID selectors; b = classes, attributes and pseudo-classes; c = type selectors and pseudo-elementsThe universal selector * and combinators count nothing.- Functional pseudo-classes
:is(), :not(), :has() = most specific argument; :where() = (0, 0, 0); :nth-child(An+B of S) = (0, 1, 0) + most specific SFrom Selectors Level 4, section 17.- Comparison
compare a, then b, then c; the first larger count wins
Limitations: what the result does not prove
- Only selector weight is calculated. Cascade layers, !important, inline styles, origin (user agent, user, author) and source order can all override a higher specificity.
- Nested rules are resolved by treating & as :is(parent list), as the CSS Nesting specification defines. Preprocessor syntax (Sass placeholders, mixins) must be compiled first.
- A selector the parser cannot read is reported with its line; it is never scored as zero.
- The stylesheet scan counts declarations roughly; it is not a full CSS validator.
Privacy: where your data goes
Everything you paste, type or drop is processed in this browser tab. It is not uploaded, logged, stored or sent to analytics. Session recording and tag-manager scripts are switched off on this page.
Standards and sources
- Selectors Level 4 - calculating specificity - checked 19 Sep 2026
- W3C - CSS Cascading and Inheritance Level 5
- W3C - CSS Nesting Module
Frequently asked questions
How is CSS specificity calculated?
Count the ID selectors, then the classes, attributes and pseudo-classes, then the element types and pseudo-elements. Write the three counts as (a, b, c) and compare them from left to right; the first column that differs decides which selector wins.
What is the specificity of :where() and :is()?
:where() always counts as zero, whatever is inside it, which makes it useful for defaults that should be easy to override. :is() takes the specificity of its most specific argument, so :is(#a, .b) counts as one ID even when .b is what matched.
Does :not() add specificity?
The :not() pseudo-class itself adds nothing, but its most specific argument does. :not(.hidden) therefore counts as one class, and :not(#x, p) counts as one ID. Older descriptions that treat :not() as zero predate Selectors Level 4.
Do pseudo-elements count as classes or types?
Pseudo-elements such as ::before and ::first-line count in the third column, alongside element types. The old single-colon forms :before, :after, :first-line and :first-letter are pseudo-elements too, and count the same way.
Does !important override specificity?
Yes. An !important declaration beats any normal declaration, whatever the selectors' weights. Between two !important declarations, specificity applies again. Relying on !important usually leads to more !important, so fixing heavy selectors is better.
How do cascade layers relate to specificity?
Layers are compared before specificity. A rule in a later @layer beats a rule in an earlier layer even if its selector is lighter, and unlayered styles beat layered ones for normal declarations. Specificity only decides between rules in the same layer.
What is the specificity of an inline style attribute?
An inline style is not a selector, so it has no specificity triple. It beats any selector-based author rule for normal declarations, which is sometimes described as an extra column in front of the ID count.
Last reviewed by the A2Z.Tools team against the sources listed above.