An ID outweighs many classes
#main a has specificity 1,0,1. .layout .card a:hover has 0,3,1. The ID selector wins this comparison when all earlier cascade conditions are equal.
Compare selectors without guessing which number matters most. Enter selectors on separate lines or in a comma-separated list to see their ID, class, and type counts, with optional sorting from strongest to weakest.
A = IDs; B = classes, attributes, and pseudo-classes; C = types and pseudo-elements. Compare left to right, without carrying digits.
| Selector | A | B | C | Tuple |
|---|---|---|---|---|
#main a | 1 | 0 | 1 | 1,0,1 |
:is(.card, #featured) a | 1 | 0 | 1 | 1,0,1 |
article .card a:hover | 0 | 2 | 2 | 0,2,2 |
:where(#main) .card a | 0 | 1 | 1 | 0,1,1 |
The largest tuple wins only after origin, importance, and cascade layer are equal. Tied selectors require scope proximity and then source order to resolve the cascade. A selector must match the element to compete.
:where() contributes zero. :is(), :not(), and :has() use the highest specificity of their argument list. :nth-child(... of ...) adds a pseudo-class plus the highest argument specificity. Inline styles and declarations such as !important are outside this selector comparison.
Selectors are parsed locally with the specificity library.
Paste selectors without CSS declarations. Use a new line or a top-level comma to separate them.
Read each A,B,C tuple from left to right: IDs, classes and similar selectors, then types and pseudo-elements.
Compare the sorted rows or export a tab-separated table. Check the other cascade conditions before deciding which declaration wins.
#main a has specificity 1,0,1. .layout .card a:hover has 0,3,1. The ID selector wins this comparison when all earlier cascade conditions are equal.
:where(#main) .card a has specificity 0,1,1 because :where() and its arguments add zero. :is(.card, #featured) a has 1,0,1 because :is() takes its most specific argument.
:is(), :not(), and :has() contribute the highest specificity among their argument selectors rather than a separate pseudo-class point. :where() contributes zero, including its arguments. :nth-child() and :nth-last-child() contribute one pseudo-class plus the most specific selector in an optional of-list. A universal selector and combinators do not add specificity.
The tuple is compared lexicographically. Ten classes do not become one ID, and there is no decimal score. Origin, importance, and cascade layers can resolve a conflict before specificity is considered. Scope proximity and then source order can break a tie. Inline styles, !important, browser support, whether a selector matches an element, and stylesheet context need separate inspection. Expand nested selectors against their parents before entering them.
A comma inside a functional pseudo-class is part of its argument list. Only top-level commas split comparison rows; commas inside attribute strings are also preserved.
For specificity, a normal pseudo-class such as :hover belongs in the B column alongside class and attribute selectors. Pseudo-elements such as ::before belong in C.
No. Enter selectors only. Declaration blocks, !important, and nested & selectors require their surrounding stylesheet context and are outside this comparison.