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:
- Higher A always wins
- If A is equal, higher B wins
- If A and B are equal, higher C wins
- 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:
!importantbeats normal rules- Between
!importantrules, 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