CSS SPECIFICITY RULES
Specificity is calculated as (a, b, c):
a = ID selectors (#id)
b = Class selectors (.class), attributes ([attr]), pseudo-classes (:hover)
c = Type selectors (div, p) and pseudo-elements (::before)
Inline styles = 1,0,0,0. !important overrides everything.
CSS Specificity Calculator
"Why isn't my CSS applying" is one of the most-asked questions in web development, and nine times out of ten the answer is specificity, not a typo. This calculates the actual weight of a selector so you can stop guessing and see exactly why one rule is beating another.
How the scoring works
Specificity is three numbers, usually written a-b-c or compared as a single value (a×100 + b×10 + c):
- a — IDs (
#header) — 100 points each, and there's basically nothing that beats an ID except another ID or an inline style - b — classes, attributes, pseudo-classes (
.active,[type="text"],:hover) — 10 points each - c — element types and pseudo-elements (
div,::before) — 1 point each - The universal selector
*and combinators (+ ~ >and whitespace) contribute nothing at all - Inline
style=""beats every stylesheet rule regardless of how many IDs are stacked on it !importantbeats everything, including inline styles — which is exactly why it should be a last resort, not a first instinct
Worked examples
p→ 0-0-1.nav-item→ 0-1-0div.container p→ 0-1-2#header .nav a:hover→ 1-2-1 — that lone ID puts it ahead of almost anything without one
The actual fix
Don't try to win a specificity war — get out of it. Style with classes, keep IDs for JavaScript hooks and anchors, and avoid !important entirely if you can, because once one rule needs it, the next override needs it too, and you end up in an arms race that makes the stylesheet impossible to reason about. Picking a methodology (BEM, or a utility-first approach like Tailwind) works precisely because it keeps every selector at roughly the same specificity, so the cascade behaves predictably instead of turning into archaeology.