CSS Specificity Calculator
See the (a,b,c) specificity of any selector, compare two to learn which wins, with a per-token breakdown — entirely on this device.
Paste a selector to see its (a, b, c) specificity and per-token breakdown.
Each part of the selector, and the component it counts toward, appears here.
Press ? for shortcuts
Do it offline:$ npx @bramus/specificity "#nav .list li a"
How to use it
- Paste one selector, or a comma-separated list; each selector in a list is scored on its own row.
- Read the (a, b, c) card, then open the token table to see which fragment lands in bucket A, B or C.
- Switch to compare mode and paste a second selector into the field beside the first.
- Read the verdict: it names the winning selector and the first component — A, then B, then C — where the two differ.
Paste a CSS selector and read its specificity as an (a, b, c) triple: A counts IDs, B counts classes, attributes and pseudo-classes, C counts element types and pseudo-elements. A per-token table shows where every point comes from. Switch to compare mode, paste a second selector, and the verdict names the winner and the component that decided it. Every calculation runs in this tab.
How it works
Specificity has three buckets. A counts ID selectors. B counts class selectors, attribute selectors and pseudo-classes such as :hover or :nth-child(). C counts element types and pseudo-elements such as ::before. The universal selector, every combinator and a namespace prefix like svg| all weigh nothing.
The :where() function is a deliberate zero — it and everything inside it add no points, so it groups selectors at no cost. By contrast :is(), :not() and :has() borrow the weight of their most specific argument, so :is(.a, #b) scores as one ID.
To compare two selectors, read the triples from the left: a larger A settles it, otherwise a larger B, otherwise a larger C. Three classes at (0, 3, 0) therefore lose to one ID at (1, 0, 0). When two selectors match exactly, the rule written later in the source order wins. Inline styles and !important sit outside the triple and override it without changing the score.
Examples
#nav .list li a(1, 1, 2)
A 1 · #nav
B 1 · .list
C 2 · li, aFour simple selectors joined by descendant spaces: #nav fills A, .list fills B, and the element types li and a fill C.
:where(#top) header nav li(0, 0, 3)
A 0 · —
B 0 · —
C 3 · header, nav, liThe :where(#top) wrapper scores zero even though it holds an ID, so A stays at 0; only the element types header, nav and li are counted, all in C.
.menu.menu.menu vs #id.menu.menu.menu → (0, 3, 0)
#id → (1, 0, 0)
Winner: #id — decided by A.Repeating .menu three times raises B to 3, yet the ID wins: A is compared before B, so (1, 0, 0) beats (0, 3, 0).
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
:where() is always worth zero
Everything inside :where() scores nothing — an ID, a class, a whole list, all zero. That is the exact opposite of :is(), which does count its argument.
:is(), :not() and :has() borrow their heaviest argument
Each takes the specificity of its single most specific argument: :is(.a, #b) counts as one ID, :not(.a.b) as two classes, and :has(> .c) as one class with the combinator free.
One colon or two, a pseudo-element still counts as a type
The legacy :before and the modern ::before both resolve to one point in C, never a class in B — the usual reason a by-hand count lands one bucket off.
Repeating a class is a real, legal boost
Writing .active.active.active is not folded to a single class; it raises B once per repeat, reaching (0, 3, 0), and the tool flags it with a note because the browser honours it.
A comma list is scored per selector
The rule h1, .title, #main is three targets sharing one declaration block. Each earns its own (a, b, c) row, and the values are never added into a single figure.
Inline styles and !important sit outside the triple
A style attribute on the element and an !important flag both beat the (a, b, c) score without changing it. This page measures selector specificity, not those two overrides.
Common errors
This selector has an unbalanced bracket, parenthesis or quote — close it and try again.- The scan reached the end of :not(.a with a parenthesis still open, so it stops rather than guess where the group closes. Balance the brackets, parentheses and quotes and the score returns at once.
Input is larger than the 1 MB limit for this tool. For bigger stylesheets use the CLI: npx @bramus/specificity 'selectors.css'- A selector is short, so a paste past one megabyte is almost always a whole stylesheet meant for another tool. The input is declined whole, and the named command reads a file of any size on your own machine.
FAQ
Does a comma-separated list add up to one number?
No. Each selector before a comma is its own rule target with its own specificity, so the tool prints one triple per selector and never totals them across the list.
Why does :where() count as zero?
By design. The CSS working group added :where() so authors could group or reset selectors without raising specificity, so the specification fixes it and its contents at zero.
Do three classes ever beat one ID?
No. The A column is always weighed before the B column, so a single ID outranks any stack of classes. Only another ID, an inline style or an !important declaration gets past it.
Does anything I paste leave my browser?
No. The selector is tokenised, scored and compared inside this page, with no server request and no account. Sharing a result is an explicit step that packs the state into a link.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Recalculate the current selector or comparison now.
- ⌘/Ctrl + S
- Download the breakdown as .json rather than saving the page.
- ⌘/Ctrl + C
- With nothing selected, copy the mode's artifact: the (a, b, c) triple in calculate, the comparison JSON in compare.
- ⌘/Ctrl + Shift + C
- Force-copy that same artifact, whether or not text is selected.
- t
- Advance to the next theme; idle while a text field has focus.
- ? or ⌘/Ctrl + /
- Open the shortcut help, including the swap-is-a-button note.
- Esc
- Close the top overlay and return focus to whatever opened it.