🎯 CSS Specificity Calculator

CSS Specificity Calculator Compare Selectors — See the (A,B,C) Score & Which Rule Wins

Enter any CSS selector and see its exact specificity score broken down into (A, B, C) — where A counts ID selectors, B counts class/attribute/pseudo-class selectors, and C counts element type and pseudo-element selectors. Compare multiple selectors simultaneously to see which rule wins in a cascade conflict. Every part of the selector is colour-coded: IDs in purple, classes and attributes in amber, elements in green. Handles :not(), :is(), :has(), :where() (0 specificity), !important indicator, and 20+ preset examples.

Colour-coded breakdownCompare multiple selectors:not(), :is(), :where()!important indicator
AdSense — 728×90 Leaderboard
🎯 CSS Specificity Calculator

Enter Selectors — See the (A,B,C) Score & Which Wins

Add CSS selectors below. Every part is colour-coded and explained. Compare multiple selectors to find the winner.

ID (#) Class / Attr / Pseudo-class Element / Pseudo-el Zero specificity
Specificity breakdown per selector
20+ Preset Examples — click to add
AdSense — 728×90 Leaderboard

CSS specificity quick reference

A
ID Selectors
(1,0,0) each
Most specific
#header(1,0,0)
#nav #item(2,0,0)
One IDbeats 100 classes
Selectorstarts with #
B
Class / Attr / Pseudo-class
(0,1,0) each
Mid-range specificity
.menu-item(0,1,0)
[type="text"](0,1,0)
:hover(0,1,0)
:where()(0,0,0)
C
Element / Pseudo-element
(0,0,1) each
Lowest specificity
div(0,0,1)
p a(0,0,2)
::before(0,0,1)
*(0,0,0)
Overrides
Above all
Use sparingly
Inline style(1,0,0,0)
!importantBeats all
@layerLayer order wins
TieLast rule wins
🌐
Check which HTTP response your CSS is loaded from.
Use the HTTP Status Code Reference to understand 304 Not Modified, caching headers and how browsers decide when to re-fetch stylesheets.
HTTP Status Codes →
⭐ Ratings

Rate this tool

4.9
★★★★★
Based on 11,200 ratings
5
10,120
4
435
3
218
2
109
1
0
Was this your selector photo guide helpful?
Thank you! G'day!
What Is CSS Specificity?

CSS Specificity Explained — How Browsers Decide Which Rule Wins

CSS specificity is the algorithm browsers use to determine which CSS rule applies to an element when two or more rules target the same element with conflicting declarations. It is one of the three components of the CSS cascade — alongside cascade origin (user agent, author, user stylesheets) and cascade order (source position). Understanding specificity is essential for writing maintainable CSS that behaves predictably.

The (A,B,C) specificity tuple

Specificity is represented as a three-number tuple (A, B, C). Each number counts a different type of selector component:

ColumnCountsSelector typesExampleScore
AID selectors#id#header(1,0,0)
BClass selectors.class.nav-item(0,1,0)
BAttribute selectors[attr][type="text"](0,1,0)
BPseudo-classes:pseudo:hover, :nth-child(2)(0,1,0)
CElement selectorselementdiv, p, a(0,0,1)
CPseudo-elements::pseudo::before, ::after(0,0,1)
Universal, combinators* + > ~ space* div > p(0,0,0)

Comparison is done column by column from left (A) to right (C). The first column with a higher number wins. If all three are equal, the last rule in the CSS source order wins.

How to read a specificity score

The selector ul#nav li.active a breaks down as: ul = +1 element (C), #nav = +1 ID (A), li = +1 element (C), .active = +1 class (B), a = +1 element (C). Total: (1, 1, 3). To beat this with another selector, you need a higher A value, or the same A with a higher B value, or the same A and B with a higher C value. One ID (1,0,0) beats (0,99,99) — columns are never carried over.

Examples

CSS Specificity Examples — Real Selector Scores

Paste any of these into the calculator above to see the colour-coded breakdown.

SelectorScoreExplanation
*(0,0,0)Universal selector — no specificity
p(0,0,1)1 element
div p(0,0,2)2 elements
.menu-item(0,1,0)1 class
p.intro(0,1,1)1 class + 1 element
ul li.active a(0,1,3)1 class + 3 elements
#header(1,0,0)1 ID — beats any B or C combination
#header .nav(1,1,0)1 ID + 1 class
#nav ul#menu li(2,0,2)2 IDs + 2 elements
a:hover(0,1,1)1 pseudo-class + 1 element
input[type="text"](0,1,1)1 attribute + 1 element
li:nth-child(2n+1)(0,1,1)1 pseudo-class + 1 element
p::before(0,0,2)1 pseudo-element + 1 element
:not(.active)(0,1,0):not() takes argument's specificity (.active = class)
:is(#id, .class)(1,0,0):is() takes most specific argument (#id = ID)
:where(#id, .class)(0,0,0):where() always 0 specificity
div.card.featured.active(0,3,1)3 classes + 1 element
#main .content p.intro a(1,2,2)1 ID + 2 classes + 2 elements
Special Cases

!important, Inline Styles, :where(), :is(), :not() — Special Specificity Rules

!important — the cascade override

!important does not have a specificity score — it is a cascade override. A declaration marked !important beats any normal (non-important) declaration regardless of specificity. When two !important declarations conflict, normal specificity rules apply between them. Using !important makes CSS harder to maintain because future overrides require yet another !important. The modern alternative is CSS Cascade Layers (@layer).

Inline styles — the implicit selector

The style attribute directly on an HTML element has the highest specificity of any selector in the author origin. It is sometimes represented as (1,0,0,0) in a four-column model. Inline styles beat any selector-based rule in your stylesheet without !important. This is why frameworks like React and Vue emit inline styles carefully — they are nearly impossible to override from a stylesheet.

:where() — always zero specificity

:where() accepts a selector list but its specificity contribution is always 0. This is deliberately designed to allow low-specificity base styles that can be easily overridden. For example, :where(article) p has specificity (0,0,1) — only the p element counts. The selector inside :where() is completely ignored for specificity purposes. This makes :where() ideal for CSS reset rules and design system foundations.

:not(), :is(), :has() — take argument specificity

These functional pseudo-classes pass through the specificity of their arguments. :not() has 0 specificity itself but counts its argument: :not(#id) contributes (1,0,0). :is() takes the specificity of its most specific argument: :is(h1, h2, h3) contributes (0,0,1) but :is(#main, .content) contributes (1,0,0) because #main is the most specific. :has() works the same way as :is() for specificity.

Combinators have 0 specificity

The combinators — descendant (space), child (>), adjacent sibling (+), and general sibling (~) — contribute nothing to specificity. div > p has specificity (0,0,2), the same as div p. The combinator type affects which elements match but not how strongly the rule wins.

Common Problems

CSS Specificity Wars — How to Fix Specificity Problems

⚠️
Problem: My style is not applying even though the selector looks right — This is almost always a specificity conflict. Another rule with higher specificity is winning. Use this calculator to compare your selector against others targeting the same element. Find the competing rule using browser DevTools: right-click the element, Inspect, look at the Styles panel — crossed-out declarations are being overridden. The winning rule and its specificity are shown.
⚠️
Problem: Overusing IDs in CSS creates unmaintainable code — ID selectors (1,0,0) are so powerful they are nearly impossible to override without adding more IDs or using !important. Best practice: use IDs for JavaScript hooks only (document.getElementById), not for styling. In CSS, use classes exclusively. If you need to override a library or third-party CSS that uses IDs, use :is(#id) .my-class to borrow the ID's specificity while keeping the class-based structure.
Solution: CSS Cascade Layers (@layer) — Introduced in CSS Cascade Level 5, @layer lets you define named layers with an explicit order. Rules in later layers win over rules in earlier layers regardless of specificity. This solves the "I need to override a framework but it has high specificity" problem without resorting to !important. Declare: @layer reset, base, components, utilities; then place rules in each layer. Utilities always win over components regardless of specificity.
Solution: BEM methodology reduces specificity problems — The BEM (Block, Element, Modifier) naming convention — .block__element--modifier — encourages using only class selectors for all styling, keeping specificity consistently at (0,1,0) throughout the codebase. When all rules have the same specificity, cascade order (source position) becomes the tiebreaker, which is predictable and easy to reason about. This is why most modern CSS frameworks and design systems use BEM or similar flat-class approaches.
Comparison

LazyTools vs Other CSS Specificity Calculators

FeatureLazyToolsspecificity.keegan.stPolypanecssbootcamp
Compare multiple selectors✅ Side-by-side + winner✅ Multiple rows❌ One at a time❌ One at a time
Colour-coded breakdown✅ ID/class/element colours✅ Yes⚠ Partial❌ No
:where(), :is(), :has()✅ All handled✅ Yes✅ Yes⚠ Partial
!important indicator✅ Yes❌ No❌ No❌ No
Bar graph visualization✅ Per selector❌ No❌ No❌ No
Preset examples✅ 20+ clickable presets❌ No❌ No❌ No
Winner ranking✅ Yes❌ No❌ No❌ No
No account required✅ Yes✅ Yes✅ Yes✅ Yes
FAQ

CSS Specificity FAQ

The algorithm browsers use to decide which CSS rule applies when multiple rules conflict. Calculated as (A,B,C): A = ID selectors, B = class/attribute/pseudo-class, C = element/pseudo-element. Higher values win. Paste any selector above to see its score instantly.

Count A: number of # ID selectors. Count B: number of .class, [attribute] and :pseudo-class selectors (not :where()). Count C: number of element type and ::pseudo-element selectors. Universal (*) and combinators (+, >, ~) contribute 0. Enter your selector above for the exact breakdown.

Yes. !important overrides all specificity levels for that property within the same cascade origin. When two !important declarations conflict, normal specificity rules apply between them. Avoid !important — use CSS Cascade Layers (@layer) instead for structured override control.

(1,0,0). One ID beats any number of classes combined — (1,0,0) always beats (0,99,99). This is why overusing IDs in CSS causes specificity problems. Best practice: use IDs only for JavaScript, not for styling.

:where() always has (0,0,0) specificity — its contents are ignored. :is() takes the specificity of its most specific argument. Use :where() when you want overridable base styles. Use :is() as a convenient shorthand that preserves specificity.

The last rule in source order wins. CSS reads top to bottom — when specificity is tied, later declarations override earlier ones. This is the foundational cascading principle.

No. * has (0,0,0). Combinators (+, >, ~, space) also have 0. :where() has 0. This means div * p has the same specificity as div p — both are (0,0,2).

:hover, :focus, :nth-child(), :first-child all add (0,1,0). Exception: :where() adds (0,0,0). :not(), :is(), :has() pass through their argument's specificity — :not(#id) contributes (1,0,0).

:not() itself has 0 specificity, but its argument counts. :not(p) adds (0,0,1). :not(.active) adds (0,1,0). :not(#main) adds (1,0,0). The :not() wrapper contributes nothing — only its contents matter.

Enter any CSS selector to see its (A,B,C) score with colour-coded breakdown. Add multiple selectors to compare and find the winner. 20+ presets. Handles :not(), :is(), :where(), !important. Free, browser-side, no account.

Best options: 1) Restructure CSS to avoid high-specificity selectors. 2) Add a class to raise specificity. 3) Use a more specific selector. 4) Move rule later in source order. 5) Use CSS @layer for structured specificity management. 6) !important as last resort.

Inline styles have (1,0,0,0) specificity — they beat any selector-based rule without !important. Avoid inline styles in complex CSS systems as they are nearly impossible to override from a stylesheet.

Almost always a specificity conflict. Compare your selector against others in this calculator. Use browser DevTools: Inspect element → Styles panel — crossed-out declarations are being overridden by the highlighted rule above them.

@layer allows you to create named, ordered layers of CSS. Later layers beat earlier layers regardless of specificity. This solves specificity wars without !important. Declare: @layer reset, base, components, utilities; then place rules in each layer.

(0,1,1) means 0 ID selectors, 1 class/attribute/pseudo-class, 1 element type. Example: p.intro = 0 IDs, 1 class (.intro), 1 element (p). To beat it you need at least (0,1,2), (0,2,0), or (1,0,0).

(0,0,1) always beats (0,0,0). Comparison is column by column. (0,0,0) is the universal selector and combinators. (0,0,1) is any element selector like p or div. Any element selector beats the universal selector.

Related tools

More Free Developer Tools