No Login Data Private Local Save

CSS Specificity Battle – Compare Two Selectors Side by Side

20
0
0
0

CSS Specificity Battle

Compare two CSS selectors side by side and see which one wins based on specificity weight. Understand how ID, class, attribute, and element selectors stack up.

SELECTOR A
VS
SELECTOR B

Quick Presets — Click to load

Understanding the Specificity Score

Specificity is expressed as four values: (a, b, c, d)a: inline styles (always 0 for selectors), b: ID selectors, c: classes / attributes / pseudo-classes, d: elements / pseudo-elements. Comparison is left-to-right: higher b wins; if equal, higher c wins, and so on. :not(), :is(), and :has() take the highest specificity from their arguments, while :where() always contributes zero.

Frequently Asked Questions

CSS specificity is the algorithm browsers use to decide which style rule applies when multiple rules target the same element. It's essentially a weight system for selectors. Understanding specificity helps you debug why certain styles aren't being applied and write more predictable CSS. The selector with the highest specificity wins; if specificity is equal, the one that appears last in the stylesheet takes precedence (the "cascade").

Specificity uses a four-column system (a, b, c, d):
a — Inline styles (1 if inline, 0 for stylesheet selectors).
b — Count of ID selectors (e.g., #header).
c — Count of class selectors (.menu), attribute selectors ([type="text"]), and pseudo-classes (:hover, :nth-child()).
d — Count of element selectors (div, p) and pseudo-elements (::before, ::after).
The universal selector *, combinators (>, +, ~, space), and :where() contribute nothing. Compare columns left to right: the first higher value wins.

These functional pseudo-classes have special behavior:
:not() — Takes the specificity of the most specific selector inside its parentheses. :not(.foo, #bar) has specificity (0,1,0,0) because #bar is an ID.
:is() — Same as :not(): uses the highest specificity among its arguments.
:has() — Also takes the highest specificity from its arguments (the "specificity of its most specific argument").
:where() — Always has zero specificity (0,0,0,0), making it perfect for creating low-specificity base styles that are easy to override.

An ID selector (#my-id) contributes to column b (0,1,0,0), while a class selector (.my-class) contributes to column c (0,0,1,0). Because comparison is left-to-right, a single ID will always beat any number of classes. For example, #header (0,1,0,0) overrides .a.b.c.d.e.f.g.h.i.j (0,0,10,0), no matter how many classes are chained. This is why many modern CSS methodologies recommend avoiding IDs for styling and using classes exclusively.

No. The universal selector * contributes zero specificity (0,0,0,0). It matches any element but doesn't add weight. For instance, *.warning has exactly the same specificity as .warning — both are (0,0,1,0). Similarly, combinators like > (child), + (adjacent sibling), ~ (general sibling), and the space (descendant) also add zero specificity.

When specificity is equal, the cascade order determines the winner: the rule that appears later in the stylesheet wins. This is a fundamental CSS principle — "last declared wins" when all else is equal. That's why placing your custom styles after third-party libraries allows you to override them without increasing specificity. It's also why :where() is useful — it lets you write styles that are intentionally easy to override later.

!important doesn't change specificity — it bypasses the normal cascade entirely. An !important declaration in a rule with low specificity will still beat a normal declaration with high specificity. However, !important is considered a last resort and should be used sparingly, as it makes stylesheets harder to debug and maintain. When two !important declarations conflict, specificity is used to break the tie. Overusing !important often indicates specificity wars in a codebase that should be resolved by refactoring selectors.

IDs have extremely high specificity (0,1,0,0) that's hard to override with class-based styles. This leads to specificity escalation where developers keep adding more IDs or resort to !important. Modern CSS best practices (including methodologies like BEM, SMACSS, and OOCSS) recommend using classes exclusively for styling. Reserve IDs for JavaScript hooks (document.getElementById) and fragment anchors. This keeps specificity flat and manageable throughout your project.