CSS Specificity Calculation - Real Case Studies
Walk through real CSS specificity calculations: nested classes, :is() with IDs, :where() defaults, !important conflicts, and how the cascade resolves them step by step.
Detailed Explanation
Three Worked Examples
Specificity is just arithmetic on a triple (IDs, classes, types). The hard part is spotting which selectors contribute. Here are three real conflicts and their resolutions.
Case 1 — Card Title Color
.card .title { color: #333; } /* (0, 2, 0) */
article h2.title { color: #000; } /* (0, 1, 2) */
For <article><h2 class="title"> inside a .card, both rules match. Compare left-to-right:
- IDs: 0 vs 0 → tie
- Classes: 2 vs 1 →
.card .titlewins
The title is #333.
Case 2 — :is() Drags in an ID
.btn { padding: 8px 16px; } /* (0, 1, 0) */
:is(#sidebar, .panel) .btn { padding: 4px 8px; } /* (1, 2, 0) */
The second rule has (1, 2, 0) because :is() borrows the highest specificity from its argument list — and #sidebar is in there. Even buttons inside .panel (no ID nearby) get the (1, 2, 0) score, which can blow up your other overrides. Refactor to :where(#sidebar, .panel) .btn if you want the lower score.
Case 3 — !important vs Inline
<p style="color: red;">Hello</p>
p { color: blue !important; }
!important in a stylesheet beats inline styles. Order of precedence (highest wins):
!importanton user-agent (UA) styles!importanton user styles!importanton author styles ← wins here- Author inline style (
style="...") - Author selector-based styles
- User styles
- UA styles
So the paragraph renders blue.
Tooling
Browser DevTools shows specificity scores on every matched rule (Chrome's Computed pane, Firefox's Inspector). When a rule "should" win but doesn't, count the IDs/classes/types on each competing selector and compare left-to-right.
Mental Shortcut
If you ever see specificity above (0, 3, 0), pause and ask whether you really need it. Most production CSS lives at (0, 1, x). Anything higher is usually a sign of an architectural smell or an overly enthusiastic :is().
Use Case
Walk through specificity calculations when debugging "why isn't my style applying?" issues. Common cases: design-system overrides being beaten by component CSS, :is() unexpectedly raising specificity, and !important arms races between vendor stylesheets and your own. Knowing the rules turns guesswork into a 30-second check.