Skip to content

CSS Specificity Calculator

Paste a CSS selector and get its specificity as (a,b,c) with a full breakdown of which IDs, classes, and elements scored where.

Why is my CSS being ignored?

You wrote .btn { color: red } and the button is still blue. Somewhere up the stylesheet, nav ul li a.btn sets it, and that selector simply outranks yours. That’s specificity at work, and it’s the single most common reason a style “doesn’t apply” when the property is spelled right and the file is loaded.

Paste the selector into the box. The calculator parses it the way a browser does and shows you the score as three numbers: (a, b, c). It also lists every piece of the selector and which bucket it landed in, so you can see exactly where the weight came from.

The three numbers, explained

Browsers don’t score specificity as one big total. They keep three separate counts and compare them left to right.

  • a counts ID selectors. Every #something adds one.
  • b counts classes, attribute selectors, and pseudo-classes. So .active, [type="text"], and :hover each add one to this column.
  • c counts type selectors (plain tag names like div or a) and pseudo-elements like ::before.

Here’s the part people forget: the columns don’t roll over. A single ID at (1,0,0) beats a selector stuffed with eleven classes at (0,11,0). Ten classes will never add up to one ID. Think of it like comparing version numbers, not adding digits together.

Two things sit outside this system entirely. An inline style="..." attribute outranks any selector you could write in a stylesheet. And !important jumps the queue ahead of everything, which is exactly why slapping it everywhere turns a stylesheet into a knife fight. The tool flags both when it spots them.

A worked example

Take #nav ul li a.active. Walk through it:

  • #nav is an ID, so a = 1
  • ul, li, a are three elements, so c = 3
  • .active is a class, so b = 1

Final score: (1, 1, 3). Now compare that to .menu .link, which scores (0, 2, 0). The first one wins on the very first column because it has an ID and the other doesn’t. The b and c counts never even get looked at. Switch the tool to “Compare two” and it’ll spell out the winner for you.

A few selectors behave oddly

Not every selector adds to the score the way you’d guess:

  • :not(), :is(), and :has() add nothing themselves. Instead they take on the specificity of their most specific argument. So :not(#main) quietly counts as an ID.
  • :where() is the escape hatch. It always contributes zero, no matter what’s inside it. Great for low-priority resets.
  • The universal selector * and combinators (>, +, ~, and the descendant space) carry no weight at all.

The parser here handles each of these cases, so you won’t get a misleading number for modern selectors.

FAQ

What do the letters a, b, c actually stand for?

They’re just labels for the three priority levels, highest first. Some people write specificity as 0-1-0 or 1,0,0 instead. The MDN docs and the CSS spec use this three-column model. The names don’t matter; the order does.

Does the calculator account for !important?

It flags it. When !important is present the tool notes that the rule jumps ahead of the normal cascade entirely, so the (a,b,c) score stops being the deciding factor against non-important rules.

Why does :not() change my score?

Because :not() inherits the specificity of whatever’s inside the parentheses. :not(p) adds one to c, while :not(#id) adds one to a. The colon and the word “not” themselves are free.

Two selectors have the same specificity. Which one wins?

Source order. When the scores tie, the rule that appears later in the stylesheet takes priority. The compare view says this explicitly when it detects a tie.

Is anything sent to a server?

Nope. The selector is parsed right in your browser with plain JavaScript. Nothing leaves the page, so you can throw production selectors at it without a second thought.

css specificity selectors cascade frontend

Related Tools

More in Developer Tools