CSS Specificity Calculator
Enter one selector per line to compare specificity; comma lists are split per selector. Invalid selectors are flagged, and layers or !important can still decide the winner.
Runs locally in your browserEnter one selector per line to compare specificity; comma lists are split per selector. Invalid selectors are flagged, and layers or !important can still decide the winner.
Runs locally in your browserEvery selector is scored with the specification’s three counters — A for ID selectors, B for classes, attributes and pseudo-classes, C for type selectors and pseudo-elements. The three examples already show the shape of the answer: #app .card:hover > h2 is 1-2-1, :where(.theme) .card:is(.featured, #hero) is 1-1-0 and main article[data-kind="docs"]::before is 0-1-3.
Selectors are validated with the browser’s own parser and scored inside the page, so nothing is uploaded. The line above the map reports how many selectors were read and which one is strongest; the copy block repeats every score as plain text.
A counts ID selectors such as #app. B counts class selectors (.card), attribute selectors ([data-kind="docs"]) and pseudo-classes (:hover, :focus-visible, :nth-child(2n+1)). C counts type selectors (main, article, h2) and pseudo-elements (::before, ::selection). The universal selector * adds nothing to any column.
Functional pseudo-classes follow the specification: :where() contributes zero, while :is(), :not(), :has() and the of list of :nth-child() are scored by their heaviest argument — that is why :is(.featured, #hero) is worth one ID. ::part() and ::slotted() count as one pseudo-element each, and the argument inside them adds nothing.
A comma list on one line is treated as what it is: several selectors. a, b becomes two rows of 0-0-1 each, and a list pasted from a stylesheet is scored selector by selector. Every row is validated with the browser’s own parser first; a line it rejects — a stray combinator, a triple colon — is still listed, tagged Invalid selector, and left out of the strongest verdict, because an invalid selector never reaches the cascade.
The score answers one question: if two of these selectors match the same element, which declaration wins on weight. Layers, !important, inline styles, order of appearance and scope proximity can still override the arithmetic, so a lower score inside an earlier @layer can win.
The whole comparison runs in the tab, so the selectors are never sent anywhere. There is no fixed line limit; the map, the verdict line and the copy block are rebuilt together as you type.
The workbench compares text, it does not apply your stylesheet: nothing is matched against a document, and the numbers are the specification’s weights rather than a prediction of the computed style. For a visual check, run the selector in the browser’s inspector on the real page.