Free tool No sign-up
CSS Specificity Calculator
Paste any CSS selector and get its (a, b, c) specificity score — with a colour-coded breakdown of every ID, class, attribute, pseudo, and element.
cssspecificityselectorscascadedebugging
Why calculate specificity?
Stop fighting !important wars
Most "why isn't my style applying" bugs are specificity issues, not browser bugs. Knowing exact (a,b,c) values lets you fix the rule rather than escalate to !important and create more debt.
Build accurate mental models
#main .card .title beats .card.featured .card.featured h2 — but only because IDs dominate. Calculating selectors out loud teaches the rules faster than memorising them.
Refactor with confidence
Before changing a deeply-nested selector, see its weight. Replacing #header > nav > ul > li > a with .nav-link is only safe if no other rule's specificity sits between them.
Teach the team
Specificity ranks alongside the cascade and inheritance as a core CSS concept. A live calculator makes code reviews faster and onboarding smoother for engineers new to a codebase.
How to use this calculator
01
Paste your selectors
Drop one selector per line. Full rules with declaration blocks work too — anything after the first { is ignored, and !important on a declaration is detected automatically.
02
Read the (a, b, c) tuple
Every selector gets a three-part score. a = IDs, b = classes / attributes / pseudo-classes, c = elements / pseudo-elements. Higher tuples win, compared left-to-right.
03
Inspect the token breakdown
Each colored chip shows which part of the selector contributed which weight. Hover for the type, and click the score to copy the (a,b,c) tuple to your clipboard.
04
Compare side-by-side
Paste competing selectors on separate lines and the calculator highlights the winner. Useful before merging a refactor that swaps an ID rule for a utility class.
Specificity reference
| Selector | Specificity | Note |
|---|---|---|
* | (0,0,0) | Universal — zero weight |
h1 | (0,0,1) | Single element |
.btn | (0,1,0) | One class |
a:hover | (0,1,1) | Element + pseudo-class |
input[type="email"] | (0,1,1) | Element + attribute |
#login | (1,0,0) | One ID |
nav ul li a | (0,0,4) | Four elements |
.card .title | (0,2,0) | Two classes |
#main .card .title | (1,2,1) | ID + 2 classes + element (.title is class) |
ul li::before | (0,0,3) | Pseudo-element counts as element |
:is(.a, #b) | (1,0,0) | :is() = highest of inner list |
:where(.anything) | (0,0,0) | :where() = always zero |
inline style attribute | (1,0,0,0) | style="…" beats any selector |
!important | overrides cascade | Last resort — escalates above all |
Specificity in practice
Basics
/* Each rule's specificity */
* { /* (0,0,0) */ }
h1 { /* (0,0,1) */ }
.btn { /* (0,1,0) */ }
#login { /* (1,0,0) */ }
nav ul li a { /* (0,0,4) */ }
#main .title { /* (1,1,0) */ } Conflict
/* Conflict — which colour wins? */
.card .title { color: red; } /* (0,2,0) */
.card .title h2 { color: blue; } /* (0,2,1) */ ← wins
#hero .title { color: green; } /* (1,1,0) */ ← wins over both
#hero .title { color: red !important; }/* !important wins */ :is/:where
/* :is() takes the highest specificity inside */
:is(.foo, #bar) p { /* (1,0,1) */ }
/* :where() always contributes 0 */
:where(.foo, #bar) p { /* (0,0,1) */ }
/* :not() takes its inner argument's specificity */
button:not(.primary) { /* (0,1,1) */ } Pro tips
01
Avoid IDs for styling
IDs add a 100-point bump that is nearly impossible to override without escalating other rules. Use classes for styling and reserve IDs for fragments and JavaScript hooks.
02
Wrap complex hooks in :where()
When you must target deeply, :where(.a .b .c) gives zero specificity. The descendant logic still applies, but other rules can override it without an arms race.
03
Flat is better than nested
Three classes (.card .header .title = 0,3,0) beat one ID (#title = 1,0,0). Keep selectors short and prefer BEM-style flat naming over deep descendant chains.
04
!important is a smell, not a tool
It works because nothing else can — including the next person trying to fix a bug. Use it only for utility classes (`.hidden { display: none !important }`) and third-party overrides.