Ultimate Design Tools
/Guides
ToolsGuidesAbout
CSSApril 2026·9 min read

CSS Specificity Explained: The Complete Guide

‘Why is my CSS not working?’ is the most common question in frontend development, and the answer is almost always specificity. Understanding how browsers decide which CSS rule wins is fundamental to writing maintainable stylesheets.

⚡ Key Takeaways
  • Master CSS specificity with this complete guide.
  • Covers 1. what is css specificity?.
  • Covers 2. how to calculate specificity.
  • Covers 3. modern css: :where(), :is(), and :has().
  • Covers 4. cascade layers (@layer).

1. What Is CSS Specificity?

Specificity is the algorithm browsers use to decide which CSS declaration applies when multiple rules target the same element and set the same property. It is calculated as a tuple of three numbers: (a, b, c) where a counts ID selectors, b counts class-level selectors, and c counts element-level selectors.

The rule with the highest specificity wins. If two rules have equal specificity, the one that appears later in the source wins. This is the cascade in Cascading Style Sheets.

2. How to Calculate Specificity

Count the selectors in each category. IDs (#header) add (1,0,0). Classes (.active), attributes ([type=text]), and pseudo-classes (:hover, :nth-child) add (0,1,0). Elements (div, p) and pseudo-elements (::before, ::after) add (0,0,1).

💡 Tip
Always include -webkit-backdrop-filter alongside backdrop-filter for Safari support. Without the prefix, the effect is invisible to roughly 25% of mobile users.

The key insight: specificity is compared left to right. One ID (1,0,0) beats any number of classes (0,99,0). One class (0,1,0) beats any number of elements (0,0,99). This is why ID selectors are so powerful — and why overusing them makes CSS hard to override.

Pro tip: Think of specificity like a number system where each column has infinite capacity. You cannot ‘carry over’ from classes to IDs. Ten classes never equal one ID.

3. Modern CSS: :where(), :is(), and :has()

:where() — Zero specificity

:where() always has zero specificity regardless of its arguments. This makes it perfect for writing defaults that are easy to override. :where(.card) .title has the same specificity as just .title.

⚠ Warning
On iOS Safari, backdrop-filter inside a position: fixed element can cause severe scroll performance issues. Test thoroughly on real iOS devices.

:is() — Takes highest argument specificity

:is() takes the specificity of its most specific argument. :is(#header, .nav) has ID-level specificity because #header is the most specific argument, even if the matched element uses .nav.

:has() — The parent selector

:has() works like :is() for specificity — it takes the specificity of its argument. div:has(.active) adds one element and one class to the count.

4. Cascade Layers (@layer)

CSS Cascade Layers, introduced with @layer, create a new priority system above specificity. Rules in later layers override earlier layers regardless of specificity. Within the same layer, normal specificity rules apply. This is a game-changer for managing large stylesheets and third-party CSS.

5. Specificity Best Practices

Calculate Your Selector's Specificity

Free. No signup. Runs 100% in your browser.

Open CSS Specificity Calculator →
✍️
Derek Giordano
Founder, Ultimate Design Tools
📚 References & Further Reading
🔗 Related Tools & Guides