About CSS Specificity Calculator
When two CSS rules set the same property on the same element, specificity decides which one wins. It is not a single number but three separate counts — IDs, then classes, then element names — compared column by column from the left. That comparison model is why one ID beats any number of classes, and why the intuitive 'add another class' fix so often changes nothing. Paste your selectors here and they are ranked from most to least specific, with the breakdown that explains the ordering.
How to use it
- 1
Paste the selectors you are comparing, one per line.
- 2
Read the ranking, which is ordered from most to least specific.
- 3
Check the ID, class and element columns to see where the difference actually lies.
- 4
If two selectors tie, remember that the one declared later in the stylesheet wins.
Three columns, compared left to right
Specificity is written as three numbers — often shown as 1-2-1 — counting IDs, then classes, then element names. The comparison walks those columns from the left and stops at the first difference, which is the detail that makes the whole system make sense. A selector with one ID and nothing else beats a selector with eleven classes, because the ID column already differs and the class column is never reached. This is why writing specificity as a single number like 100 is misleading: it implies that enough classes could add up to an ID, and they cannot. The three categories are: IDs in the first column; classes, attribute selectors and pseudo-classes in the second; and element names and pseudo-elements in the third. The universal selector and combinators such as the child and descendant combinators contribute nothing at all, so `.card > p` and `.card p` have identical specificity despite matching very different things. Inline styles sit above all of this, and !important sits above that.
The functional pseudo-classes behave differently from each other
Selectors Level 4 added several functional pseudo-classes with deliberately different specificity behaviour, and knowing which is which is genuinely useful. :is(), :not() and :has() all take the specificity of their most specific argument, which means :not(#main) contributes a full ID even though it is expressed as a negation — an easy way to accidentally create a very hard-to-override rule. :where() is the deliberate exception and always contributes zero, no matter what is inside it. That makes :where() the right tool for reset styles, default theming and library base styles, because it lets you write a precise selector that any later rule can override with a single class. Rewriting a heavy base selector to wrap it in :where() is often the cleanest way to fix a stylesheet where everything has to fight the defaults. The layered alternative is @layer, which resolves conflicts by layer order before specificity is even consulted.
What people use it for
Working out why a style is not applying
The usual answer is that another selector is more specific, and comparing them side by side shows exactly where.
Avoiding !important
Seeing the competing values usually reveals a smaller change that wins properly, without starting an important war.
Reviewing a stylesheet's health
Selectors scoring high on IDs are the ones that will be hard to override later, and are worth refactoring early.
Understanding :is(), :has() and :where()
These behave differently from one another, and seeing the computed value makes the difference concrete.
A few pointers
- Wrap reset and default styles in :where() so they contribute zero specificity and are trivially overridden.
- Avoid ID selectors for styling — they create a specificity ceiling that later rules cannot beat without another ID or !important.
- When two selectors tie, source order decides, so check the order your stylesheets load in before assuming a rule is broken.