CSS Specificity Calculator - Understand Selector Weight
Developer Tools
Compare CSS selector specificity using modern (A,B,C) and legacy (a,b,c,d) scores, token breakdowns, Selectors Level 4 pseudos, and cascade demos.
Examples
Legacy specificity (a,b,c,d)
(0,1,2,1)
Selectors Level 4 (A,B,C): (1,2,1)
Token contributions
Each chip shows its legacy tuple contribution and the running total after that token.
#headerID+ (0,1,0,0)Running: (0,1,0,0).navClass+ (0,0,1,0)Running: (0,1,1,0)aType+ (0,0,0,1)Running: (0,1,1,1):hoverPseudo-class+ (0,0,1,0)Running: (0,1,2,1)
Best-effort parser: escaped identifiers, namespace selectors, selector-bearing pseudo-classes such as :nth-child(... of ...), advanced pseudo-elements, and selector-list matching may need a full CSS parser.
Cascade beyond specificity
These are small teaching examples for same-origin declarations, not a full CSS cascade engine.
How to use this tool
- Enter selector. Type a CSS selector like #header .nav > a:hover into the input.
- Read the score. Read the modern (A,B,C) tuple alongside its legacy (a,b,c,d) mapping and inspect token contributions.
- Compare selectors. Add multiple selectors (one per line) to the Compare tab to rank them.
- Use examples. Click any example to load it and see how it is scored.
How CSS specificity works
CSS specificity helps decide which declaration wins when competing rules target the same element. It is one part of the cascade: origin, importance, cascade layers, and other cascade conditions can be considered before specificity. This calculator scores selectors only, so its inline-style weight stays at zero.
Selectors Level 4 expresses specificity as (A,B,C). This page also shows the legacy four-part form (a,b,c,d), where a is inline-style weight and is 0 for selector-only calculations. The remaining columns map directly: b = A for IDs, c = B for classes, attributes, and pseudo-classes, and d = C for types and pseudo-elements.
- A / b: ID selectors (
#id) - B / c: Class selectors (
.class), attribute selectors ([attr]), and pseudo-classes (:hover,:nth-child) - C / d: Type selectors (
div,p) and pseudo-elements (::before,::after)
Within the relevant cascade origin, importance, and layer, specificity compares
lexicographically: a larger value in an earlier column wins before later columns are
considered. The universal selector (*) and combinators (>,
+, ~) contribute zero.
Modern pseudo-class specificity
:where(): Always 0. Useful for base styles you want easily overridden.-
:is(),:not(), and:has()use the specificity of their most specific argument.
Tips for managing specificity
- Prefer classes over IDs in CSS to keep specificity manageable.
- Avoid nesting selectors too deeply, as each level adds to specificity.
-
Use
:where()for reusable utilities that should never win a specificity battle. - Reserve
!importantfor truly exceptional cases like utility overrides.
!important
!important changes cascade priority; it is not a specificity value. For these same-origin
declarations, an important declaration beats a normal declaration even when the normal selector
has higher specificity. The complete cascade still considers origin and layer priority, so importance
does not mean a declaration wins every possible cascade comparison. The interactive example above
toggles importance to show how the winner changes.
.button {
color: blue !important; /* Competes in the important-declaration cascade */
} Why to use it sparingly: Important declarations have their own cascade ordering and can make later overrides harder to reason about. Prefer a clear layer and selector strategy when you control the stylesheet.
When it is useful: Utility classes that must override component styles, third-party styles you cannot control, or critical accessibility fixes.
Cascade layers (@layer)
CSS cascade layers let you define an order for groups of rules. Among normal declarations in
different layers, the later layer has priority before specificity is compared. Among important
declarations in different layers, the earlier layer has priority. Unlayered rules also have
defined positions in the cascade, so a layer name such as utilities is not inherently
highest priority. The control above demonstrates the normal-declaration rule with two layers and
selectors of different specificity.
@layer reset, base, components, utilities;
@layer reset {
* { margin: 0; padding: 0; }
}
@layer utilities {
.hidden { display: none !important; }
} For normal declarations, the last declared layer wins when declarations from different layers compete, even if its selector is less specific. Within one layer, specificity still matters. For important declarations, layer order reverses and the first layer has priority.
Specificity visualization
Compare these three selectors:
| Selector | Specificity (a,b,c,d) | Explanation |
|---|---|---|
p | (0,0,0,1) | 1 type selector |
.button | (0,0,1,0) | 1 class |
#header .nav a:hover | (0,1,2,1) | 1 ID + 1 class + 1 pseudo-class + 1 type |
Winner: #header .nav a:hover because it has an ID (A=1, or legacy b=1). Even if .button had 100 classes, it would still lose because b=0.
Frequently asked questions
What do the four numbers (a,b,c,d) mean?
In legacy (a,b,c,d) notation, a is inline-style weight and is 0 for selector-only calculations; b is IDs, c is classes/attributes/pseudo-classes, and d is types/pseudo-elements. Selectors Level 4 uses (A,B,C): A=b, B=c, and C=d.
Does !important affect specificity?
!important is a cascade priority, not a specificity value. For same-origin declarations, an important declaration outranks a normal declaration before selector specificity is compared. Other cascade factors, including origin and layer priority, still matter.
How does @layer order affect normal declarations?
Among normal declarations in different layers, the later layer wins before specificity is compared. For important declarations, layer order reverses and the earlier layer wins.
What is the specificity of :where()?
:where() always contributes 0 specificity, regardless of its arguments. This is by design, to allow easy overrides.
How does :not() affect specificity?
:not() itself contributes 0. The specificity comes from the most specific argument inside it. For example, :not(.active) has specificity (0,0,1,0).
Related tools
- CSS FormatterUse CSS Formatter to beautify or minify CSS online. Adds indentation and.
- CSS Variable ExtractorUse CSS Variable Extractor to paste any CSS and instantly extract all custom.
- CSS GridUse CSS Grid to visually build CSS grid layouts. Define rows, columns,.
- FlexboxUse Flexbox to experiment with all CSS flexbox properties in a.