PureDevTools

CSS Specificity Calculator

Calculate and visualize CSS selector specificity — color-coded token breakdown, side-by-side comparison, :is()/:where() support

All processing happens in your browser. No data is sent to any server.

One selector per line. Each part is color-coded: red = ID, amber = class/attr/pseudo-class, blue = element/pseudo-element.

Specificity Score Reference (0,b,c,d)

#id(0,1,0,0)ID selector
.class(0,0,1,0)Class selector
div(0,0,0,1)Type selector
[attr](0,0,1,0)Attribute selector
:hover(0,0,1,0)Pseudo-class
::before(0,0,0,1)Pseudo-element
:is(#id, .c)(0,1,0,0):is() — most specific arg
:where(#id)(0,0,0,0):where() — zero specificity
*(0,0,0,0)Universal selector

Your .active class override is being ignored — something with higher specificity is winning, but you can’t tell what. You open DevTools, see a crossed-out rule, scroll up to find the winning selector, and try to mentally compute (0,1,2) vs (0,2,1). For simple selectors this works. For :is(#header, .nav) .item:not(.disabled)::before? You need a calculator.

Why This Calculator (Not the Selector Specificity Calculator)

PureDevTools has a CSS Selector Specificity Calculator that uses the three-column (a,b,c) model with color-coded token breakdown. This tool uses the four-column (inline, id, class, element) model — matching how browser DevTools display specificity — with visual component bars for side-by-side comparison. Both handle :is(), :not(), :has(), and :where() correctly. Pick whichever model you’re more comfortable with. Everything runs in your browser; no data is sent anywhere.

What Is CSS Specificity?

CSS specificity is the algorithm browsers use to decide which CSS rule wins when multiple rules target the same element. Every selector has a four-part specificity score — (inline, id, class, element) — and the rule with the highest score takes precedence.

Understanding specificity is essential for writing maintainable CSS. Without it, seemingly random style overrides, unexpected cascade behavior, and overuse of !important become unavoidable.

/* Which color wins on a <div class="card" id="hero">? */
div { color: red; }           /* (0,0,0,1) */
.card { color: blue; }        /* (0,0,1,0) */
#hero { color: green; }       /* (0,1,0,0) — wins */

The Specificity Score (a,b,c,d)

CSS specificity is expressed as a four-column value. Higher values in earlier columns always beat higher values in later columns — they are not decimal digits. Column b=1 always beats any value of c or d.

ColumnLabelWhat countsColor
aInlineInline style="" attributePurple
bID#id selectorsRed
cClass / Attr / Pseudo-class.class, [attr], :hover, :nth-child()Amber
dType / Pseudo-elementdiv, span, ::before, ::afterBlue

Quick Reference

*                         /* (0,0,0,0) — zero specificity */
div                       /* (0,0,0,1) */
.foo                      /* (0,0,1,0) */
#bar                      /* (0,1,0,0) */
div.foo                   /* (0,0,1,1) */
nav > ul li               /* (0,0,0,3) */
a:hover                   /* (0,0,1,1) */
.nav .item:first-child    /* (0,0,3,0) */
#content p.intro          /* (0,1,1,1) */
input[type="text"]:focus  /* (0,0,2,1) */

How the Calculator Works

Paste one or more CSS selectors — one per line — and the tool:

  1. Tokenizes each selector into individual parts (ID, class, attribute, type, pseudo-class, pseudo-element)
  2. Color-codes each token by its specificity column (red = ID, amber = class/attr/pseudo-class, blue = element/pseudo-element)
  3. Computes the (0,b,c,d) score per selector following the CSS Selectors Level 4 spec
  4. Ranks multiple selectors from highest to lowest specificity with a visual comparison bar
  5. Detects parse errors for malformed selectors

Everything runs entirely in your browser. No selector is sent to a server.

Specificity Rules You Need to Know

1. Inline Styles Always Win (column a)

An inline style="" attribute has specificity (1,0,0,0) — higher than any selector you can write in a stylesheet, except !important.

<!-- This green wins over any external .card { color: red } -->
<div class="card" style="color: green">...</div>

2. !important Overrides Specificity

!important is not part of the specificity calculation. It creates a separate cascade layer that beats everything else. Two !important rules fall back to specificity to break the tie — but cascading !important overrides is a maintainability anti-pattern.

3. The Universal Selector (*) Has Zero Specificity

* { ... } matches everything but contributes zero to any specificity column. Combinators (>, +, ~, ) also have zero specificity.

4. :is(), :not(), :has() Take the Specificity of Their Most Specific Argument

/* :is(#id, .class) → takes (0,1,0,0) from #id */
:is(#id, .class) {}   /* specificity: (0,1,0,0) */

/* :not(.foo) → (0,0,1,0) — specificity from .foo */
:not(.foo) {}         /* specificity: (0,0,1,0) */

/* :has(> .child) → (0,0,1,0) — specificity from .child */
div:has(> .child) {}  /* specificity: (0,0,1,1) */

5. :where() Always Has Zero Specificity

:where() was designed specifically to allow zero-specificity grouping. No matter how specific the selectors inside are, :where() contributes (0,0,0,0).

:where(#id) .btn {}   /* (0,0,1,0) — #id zeroed by :where() */
.nav .btn {}          /* (0,0,2,0) — higher specificity */

6. Pseudo-Elements Count as Type Selectors (column d)

::before, ::after, ::placeholder, ::first-line, and all other pseudo-elements add to column d. Legacy single-colon notation (:before, :after) is treated identically.

p::first-line { }  /* (0,0,0,2) — p(d=1) + ::first-line(d=1) */

7. Attribute Selectors Count as Classes (column c)

[type="text"], [href^="https"], [data-active] — all attribute selectors, regardless of complexity, each count as one class-level (c) token.

input[type="text"]   /* (0,0,1,1) — [type="text"](c=1), input(d=1) */
a[href][title]       /* (0,0,2,1) — two attribute selectors (c=2), a(d=1) */

Color-Coded Token Breakdown

This calculator highlights each part of your selector so you can see at a glance what’s contributing specificity and how much.

ColorColumnToken types
RedID (b)#header, #nav, #main
AmberClass (c).card, [data-active], :hover, :nth-child(2n)
BlueElement (d)div, a, span, ::before, ::after
GrayNone*, combinators (>, +, ~), :where(...)

Comparing Multiple Selectors

Enter one selector per line to compare specificity side by side. The tool ranks all selectors from highest to lowest and shows a normalized bar chart so you can visually see the difference in weight.

This is especially useful for:

Specificity in Practice

Problem: Overriding Component Styles

/* Component CSS */
.button { background: blue; }        /* (0,0,1,0) */

/* Page override — fails to win */
.sidebar .button { background: red; }  /* (0,0,2,0) — wins */

When you need to lower specificity to make overrides easier, use :where():

:where(.sidebar) .button { background: red; }  /* (0,0,1,0) — ties */

Problem: Understanding Complex Selectors

/* Step-by-step breakdown */
nav.primary > ul li.active::before
/* nav      → d=1
   .primary → c=1
   ul       → d=2 (combinator > ignored)
   li       → d=3
   .active  → c=2
   ::before → d=4
   Result:  (0,0,2,4) */

CSS Cascade Layers and Specificity

CSS @layer adds a separate dimension on top of specificity. Rules in higher layers win over rules in lower layers regardless of specificity. Within a single layer, specificity applies normally.

@layer base, components, utilities;

@layer base {
  #id { color: red; }         /* (0,1,0,0) — loses to utilities layer */
}
@layer utilities {
  .text-blue { color: blue; } /* (0,0,1,0) — wins despite lower specificity */
}

Frequently Asked Questions

Does the order of selectors in a stylesheet affect specificity? No. Specificity is calculated from the selector structure alone. Source order only matters when two rules have equal specificity — the later rule wins.

Does combining classes increase specificity? Yes. .foo.bar has specificity (0,0,2,0) — two class tokens. Each class, attribute, or pseudo-class selector you add increments column c.

Why does :nth-child(2n+1) count as class-level? All pseudo-classes — including :nth-child(), :nth-of-type(), :lang(), :focus-within — contribute to column c. The complexity of their argument doesn’t matter; each pseudo-class is one token (except :is(), :not(), :has(), which use their argument’s specificity).

What is the maximum specificity? Technically unlimited — you can chain as many ID, class, or type selectors as you like. In practice, any specificity above (0,1,0,0) often indicates overly specific CSS that should be refactored.

Can I use the specificity score to debug why a style isn’t applying? Yes. Open browser DevTools → Elements → Styles. Crossed-out rules are overridden by higher-specificity rules shown above them. Paste both selectors into this calculator to immediately see which one wins and why.

What is the difference between :is() and :where()? Both accept a selector list as their argument, but they differ in specificity. :is() takes the specificity of its most specific argument. :where() always contributes zero specificity. Use :where() when you want base styles that are easy to override; use :is() when you need to group selectors while preserving their specificity.

Related Tools

More CSS Tools