CSS Specificity Demystified

by Dustin Tantum | Web Development | 0 comments

Decoding Chrome DevTools’ Three-Number TooltipS

If you’ve ever inspected an element in Chrome DevTools and hovered over a CSS rule, you’ve probably noticed a small tooltip showing three comma-separated numbers labeled specificity.

For many developers, those numbers are familiar—but not always fully understood.

CSS specificity is one of the most common sources of styling bugs, unexpected overrides, and escalating selector complexity. When styles don’t apply as expected, the root cause is often not missing CSS, but losing the specificity battle.

This article explains exactly how Chrome calculates those three values, what each number represents, and how the browser uses them to decide which rule wins. By the end, you’ll be able to look at a specificity tuple and immediately understand why a rule applies—or why it doesn’t.

This is one of those DevTools features that’s incredibly useful once you really understand it.

How it Works

When Chrome shows a CSS rule’s specificity as three comma-separated numbers, it’s using this model:

(A, B, C)

Each position represents a different class of selector, ordered from most powerful to least powerful.

IDs > Classes > Elements Quantity only matters within the same tier

1. Specificity Breakdown

A — ID selectors

Counts how many ID selectors are in the rule.

#header { }
Specificity: (1, 0, 0)

B — Class-level selectors

Counts:

  • .class
  • [attribute]
  • :pseudo-class (e.g. :hover, :focus, :nth-child())
.nav.primary:hover { }
Specificity: (0, 3, 0)

(.nav, .primary, :hover)

C — Type selectors

Counts:

  • HTML elements (div, p, a)
  • ::pseudo-elements (e.g. ::before, ::after)
ul li a::after { }
Specificity: (0, 0, 4)

(ul, li, a, ::after)

2. How the Numbers Are Used

CSS compares specificity left to right, like version numbers:

  1. Higher A always wins
  2. If A is equal, higher B wins
  3. If A and B are equal, higher C wins
  4. If all equal → later rule in the stylesheet wins

Example:

(0, 1, 10)  beats  (0, 0, 1000)

Classes beat elements, no matter how many elements you stack.

3. Common Examples in DevTools

Selector Specificity
div (0,0,1)
.card (0,1,0)
#app (1,0,0)
div.card (0,1,1)
#app .card (1,1,0)
ul li a.active (0,1,3)

4. Special (and Often Misunderstood) Cases

(* Universal selector)

* { }
(0,0,0)

It adds no specificity.

:not()

button:not(.primary)

Only the argument counts:

(0,1,1)

!important

Not part of specificity at all.

Think of it as a separate override tier:

  • !important beats normal rules
  • Between !important rules, specificity applies again

5. Why This Matters in Real Projects

Anti-pattern to watch for

If you see numbers like:

(0, 8, 12)

That’s a smell. It usually means:

  • Over-nested selectors
  • Fighting CSS instead of structuring it

Best practice

Aim for:

  • Low A (avoid IDs in CSS)
  • Moderate B
  • Minimal C

This keeps styles predictable and override-friendly.

In Conclusion

CSS specificity isn’t magic, and it isn’t arbitrary—it’s a deterministic scoring system that Chrome exposes directly in DevTools. Those three numbers represent a hierarchy of selector power, compared left-to-right, and they explain nearly every “why is my CSS being ignored?” moment you’ll encounter.

More importantly, understanding specificity isn’t just about debugging—it’s about writing better CSS in the first place. Low, predictable specificity leads to styles that are easier to reason about, easier to override, and far less likely to require !important as a last resort.

The next time a rule is crossed out in DevTools, don’t guess. Hover, read the numbers, and let specificity tell you the story.

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

IT Guides

Practical tips and step-by-step strategies for the IT choices small businesses face every day. When the path isn’t obvious, Nurbid guides.

Table of Contents