Skip to main content

CSS Specificity Calculator — Compute Any Selector's (a, b, c) Score

Paste any CSS selector and instantly get its specificity as (a, b, c) per CSS Selectors Level 4. Handles :is(), :not(), :has(),:where(), attribute selectors, pseudo-elements, and combinators correctly. Compare two selectors side-by-side to settle which rule wins the cascade. Free, no signup, 100% in your browser.

Samples:
CSS selector

IDs (a)

0

Classes (b)

3

Elements (c)

0

Breakdown

.card[].title:hover

Selectors Level 4 Spec

Returns specificity as (a, b, c) triple per the modern CSS Selectors Level 4 spec. Correctly handles :is(), :not(), :has() (max of args), and :where() (always 0).

Compare Mode

Paste two selectors and the tool names the winner and the deciding column (a, b, or c). Settles "why is the wrong rule applying" bugs in seconds.

Token Breakdown

Each part of the selector is colored and labeled (ID / class / attribute / pseudo-class / pseudo-element / element / combinator) so you see exactly where the weight comes from.

100% Client-Side

All parsing runs in your browser via custom JavaScript — no fetch, no signup. Works offline once loaded.

CSS Specificity Calculator: Compute Any Selector's (a, b, c) Score

A CSS specificity calculator tells you which rule wins the cascade by scoring a selector as a triple (a, b, c): a = ID selectors, b = class, attribute, and pseudo-class selectors, c = element and pseudo-element selectors. Paste a selector and this tool returns its score per CSS Selectors Level 4, with a per-token breakdown and a compare mode that settles which of two rules wins. It runs 100% in your browser, free.

How to calculate CSS specificity

  1. Paste a selector such as main #content .card .button:hover into the input — the score updates as you type.
  2. Read the (a, b, c) result and the colored token breakdown showing where each point comes from (ID, class, attribute, pseudo-class, pseudo-element, element, combinator).
  3. Open Compare mode and paste a second selector to see which of two competing rules wins, and by which column.
  4. Load a sample selector (10 are pre-built, covering :is(), :where(), attribute, and pseudo-element cases) to learn the rules fast.
  5. To lower a score, swap an ID for a class or wrap part of the selector in :where(), then re-check the new (a, b, c).

How specificity decides which rule wins

Browsers compare the three columns left to right, not as one number. A selector with a higher a beats any selector with a lower a, regardless of b and c. Only when a ties do they compare b, then c. If all three tie, the rule that appears later in the source wins. The exact algorithm is defined in the MDN Specificity reference and the W3C Selectors Level 4 specification, which every major browser conforms to.

Combinators (>, +, ~, and the descendant space) add nothing to the score; they only change which elements match. The universal selector * also adds zero. Three functional pseudo-classes are special: :is(), :not(), and :has() take the maximum specificity of their arguments, while :where() always counts as (0, 0, 0) no matter what it wraps.

Worked examples: selector → score

#main .card → (1, 1, 0)

One ID and one class. This beats any rule made only of classes and elements, however long.

header nav ul li a → (0, 0, 5)

Five element names, zero classes. A single class rule .link at (0, 1, 0) outranks it outright.

.row :is(h1, h2, .title) → (0, 2, 0)

The descendant .row adds one class; :is() takes the max of its arguments, and .title (one class) outweighs h1, adding a second class. Swap :is for :where and the wrapper contributes zero, dropping the whole selector to (0, 1, 0) — just .row.

Edge case · :not() inflates more than you expect

p:not(.intro):not(.footer) scores (0, 2, 1), not (0, 0, 1). The :not() pseudo-class itself is free, but it inherits the max specificity of its argument — each .intro and .footer adds one class. Two negations means two classes.

Pair this with the CSS Beautifier to read the stylesheet you are debugging, the CSS Minifier to compress it for production, and the Color Contrast Checker to verify accessibility once the cascade resolves.

CSS Specificity Rules — What Counts & What Does Not

Selector PartWeight AddedNotes
Inline style (style attribute)(1, 0, 0, 0) — beats every selectorPer spec, inline style is a separate dimension above selectors. CSS-in-JS often emits it.
ID selector (#id)adds 1 to "a"IDs are heavy — avoid using them in stylesheets when classes will do.
Class (.cls)adds 1 to "b"Workhorse selector. Stack two classes (.btn.btn) to outweigh a single class without raising ID count.
Attribute ([type="text"])adds 1 to "b"Same weight as a class — useful for form-state styling without classes.
Pseudo-class (:hover, :focus)adds 1 to "b"Includes :is(), :has() which inherit max specificity of arguments.
Element (div, span)adds 1 to "c"Lightest — most selectors involve at least one element name.
Pseudo-element (::before)adds 1 to "c"Same weight as element. Double-colon syntax is modern; single-colon is legacy alias.
* universal selectoradds 0 to allPure noise for specificity — only useful for cascading effects.
Combinators (>, +, ~, space)0Direction/relationship, not weight. Do not affect specificity.
:where(X) — special0Argument specificity is DISCARDED. Use :where to opt out of specificity wars.
:is(X) / :not(X) / :has(X)takes MAX of argument specificityLets you express alternatives without inflating beyond the heaviest alternative.

Five Common Specificity Problems & Fixes

1. Style not applying

Compute specificity of the rule you want vs the rule that won. Whichever has higher (a, b, c) wins. Bump yours by adding a class, NOT an ID.

2. Two rules with same specificity

CSS uses source order: whichever appears LATER in the stylesheet wins. Reorder or use a more specific selector.

3. !important war

Avoid !important except for utility classes (e.g. .hidden { display: none !important }). One !important beats specificity; two !importants compete by specificity.

4. Inline style wins everything

Inline style="..." beats every stylesheet selector except !important. Move to a class-based rule or use :is() to lift cascade weight.

5. Component styles stomping app

Wrap library/component styles in :where(.lib) — specificity contributes 0, so app rules always win.

Four Specificity Best Practices for 2026

1. Keep Specificity Flat

Aim for (0, 1, 0) or (0, 2, 0) for most rules — one or two classes. Component-driven CSS pairs naturally with low-specificity selectors that compose cleanly.

2. Avoid IDs in Stylesheets

ID selectors are heavy and locked to single elements. Use classes for styling, reserve IDs for JS hooks and accessibility relationships (aria-labelledby).

3. Use :where() for Library Styles

Component libraries should wrap their CSS in :where(.lib) so application code can override with a single class. Modern CSS-in-JS libraries embrace this pattern.

4. !important Is a Last Resort

Use !important only for utility classes that MUST win (e.g. .visually-hidden). For everything else, raise the specificity slightly with an additional class — never via ID, never via !important.

The "256 classes beat an ID" myth, settled

You may have read that 256 chained classes (.a.a.a…) overflow into the ID column and beat a single #id. That was a real bug in old IE, Gecko, and WebKit builds, where each column was stored in an 8-bit field that wrapped at 256. It is not the spec, and no current browser does it. The spec uses a number system with a base large enough that the columns never carry — so (0, 256, 0) still loses to (1, 0, 0). Treat each column as a separate tier, never as a decimal score.

One thing to know about this calculator: it shows an internal "score" only to size the comparison bars and sort results — it deliberately weights columns as a×10000 + b×100 + c. That packed number is for the UI alone and would misrank pathological selectors with 100+ classes. The win/lose verdict and the (a, b, c) readout always use true column-by-column comparison, exactly as browsers do.

Runs 100% in your browser

Your selectors never leave your device. Parsing happens locally in JavaScript with no network request, so the tool works offline once the page loads — no uploads, nothing leaves your device. I tested it against the tricky cases that trip up most calculators: input[type="text"]:focus, nested :not() chains, :nth-child(2n+1 of .row), double-colon versus legacy single-colon pseudo-elements, and the universal selector. Each result matches what Chrome and Firefox DevTools report for the same rule.

Last updated: June 2, 2026 · Runs 100% in your browser — no uploads, nothing leaves your device.

Need a different tool?

Browse all 89 free, in-browser tools — or tell us what we should build next.

Browse all tools