Selector
Result
Compare Selectors
A Wins
WinnerA wins because it has 1 ID and B has 0. The ID column is compared first.
| Category | Selector A | Selector B | Verdict / Diff |
|---|
When !important is declared on both sides, the standard specificity comparison still applies between them.
Cascade layers (@layer) and origins (user-agent vs author) also affect final styles; this tool evaluates selector specificity along with the inline and !important flags above.
Analyze a CSS File
Learn CSS Specificity
1. What is CSS specificity?
CSS specificity is the weight algorithm browsers use to resolve conflicting CSS declarations targeting the same HTML element. When two or more selectors match an element, the declaration associated with the most specific selector wins and applies its styles.
A Simple Analogy: Think of specificity like weight classes in boxing or military ranks. A single heavyweight outmatches any number of lightweights, just as a single general outranks any battalion of privates. In CSS, an ID selector outranks any number of classes, and a class outranks any number of bare element tags.
2. How is it calculated? (The 3-Column Tuple)
Specificity is measured as a 3-part tuple: (A, B, C). Each category contributes to its designated column:
| Category | Column | Target Selectors | Contribution |
|---|---|---|---|
| IDs | Column A | #header, #nav |
+1, 0, 0 |
| Classes & Attributes | Column B | .card, [type="text"], :hover |
+0, 1, 0 |
| Elements & Pseudos | Column C | div, p, ::before, ::after |
+0, 0, 1 |
Comparison Rule: Tuples are compared lexicographically from left to right. Column A is evaluated first. If tied, Column B is evaluated. Only if both A and B are equal is Column C checked.
#header .nav ul li.active → Specificity 1 - 2 - 2
3. What is ignored? (The Non-Base-10 Rule)
These parts contribute [0, 0, 0] to specificity:
- Universal selector:
*adds 0 - Combinators: Descendant (space), child (
>), adjacent sibling (+), and general sibling (~) add 0 - The zero-specificity pseudo-class:
:where(...)always contributes[0, 0, 0]regardless of what is inside it.
CRUCIAL WARNING: Specificity is NOT base-10!
A very common beginner trap is thinking (0, 1, 0) = 10 and (0, 0, 11) = 11. Numbers in CSS specificity never carry over into adjacent columns. 11 classes (0 - 11 - 0) will never beat 1 ID (1 - 0 - 0).
(0 - 11 - 0)
4. Special Selectors (CSS Selectors Level 4 Rules)
Modern functional pseudo-classes follow recursive evaluation rules specified in CSS Selectors Level 4:
| Selector | Specificity Contribution | Example |
|---|---|---|
:is(A, B) |
Takes specificity of the most specific argument | :is(#nav, .menu) → [1, 0, 0] |
:not(A, B) |
Takes specificity of the most specific argument | :not(.disabled, a) → [0, 1, 0] |
:has(A, B) |
Takes specificity of the most specific argument | div:has(> #hero) → [1, 0, 1] |
:where(...) |
Always zero: [0, 0, 0] |
:where(#app, .btn) → [0, 0, 0] |
:nth-child(An+B of S) |
[0, 1, 0] + max specificity of selector list S |
:nth-child(odd of .item) → [0, 2, 0] |
::slotted(S) |
[0, 0, 1] + max specificity of selector S |
::slotted(.slot-item) → [0, 1, 1] |
:host(S) |
[0, 1, 0] + max specificity of selector S |
:host(.active) → [0, 2, 0] |
:is() and :not() combinations
5. Inline styles, !important and the Cascade Order
Selector specificity is only one step in the broader CSS Cascade algorithm. The definitive order of precedence is:
!importantdeclarations: Overrides inline styles and normal specificity rules.- Inline styles: Properties set directly on elements (
style="...") beat all external and internal stylesheet rules. - Selector Specificity: The highest
(A, B, C)tuple wins. - Source Order: When specificity is identical, the rule appearing later in the CSS wins.
Important note: When !important is applied to both conflicting rules, the standard specificity comparison still decides which one wins!
6. Architectural Best Practices
- Keep specificity flat and low: Prefer single or double class selectors (e.g., BEM
.card__title). Low specificity ensures styles can be overridden cleanly anywhere. - Avoid IDs for styling: Reserve IDs for HTML anchors and JS hooks. Using an ID in CSS forces you to use another ID or
!importantto override it. - Avoid
!important: Treat!importantas a code smell. It creates maintainability deadlocks. - Use
:where()for resets and base styles: Wrapping design system primitives in:where(...)keeps their specificity at 0, allowing consumer components to override them without resistance. - Adopt CSS Cascade Layers (
@layer): Use layers (e.g.,@layer reset, base, components, utilities;) to control priority across large codebases without inflating selector specificity. - Keep selector chains short: Avoid over-qualifying elements like
div.card ul.list li.item; write.list__iteminstead.
:where()
7. Common Mistakes & Pitfalls
- Over-qualifying selectors: Writing
ul.navordiv.sidebarinstead of just.navor.sidebar. This adds unnecessary element specificity and couples your CSS to HTML tag choices. - Chaining excessive classes: Writing
.card.featured.active.primary.largeto win an override battle rather than refactoring CSS architecture. - Forgetting that source order breaks ties: If two selectors have identical specificity (e.g., both
0 - 1 - 0), whichever rule comes later in the stylesheet wins. - Assuming
:where()takes argument specificity::where()is specifically designed to always have 0 specificity; use:is()if you want argument specificity.
Engine Self-Test (CSS Selectors Level 4 Specification)
30 / 30 Passed
| Status | Selector | Expected Specificity | Actual Specificity | Notes / Verdict |
|---|