CSS Specificity and Cascade
What is Specificity?
When multiple CSS rules target the same element, the browser uses specificity to determine which rule wins. Specificity is calculated as a score — the rule with the highest score is applied.
Specificity is calculated using four categories (A, B, C, D):
| Category | What counts | Score |
|---|---|---|
| A — Inline styles | style="..." attribute | 1,0,0,0 |
| B — ID selectors | #id | 0,1,0,0 |
| C — Class, attribute, pseudo-class | .class, [attr], :hover | 0,0,1,0 |
| D — Element, pseudo-element | div, p, ::before | 0,0,0,1 |
/*
* Specificity scores (A, B, C, D):
*
* * → 0,0,0,0 (universal)
* p → 0,0,0,1 (element)
* .class → 0,0,1,0 (class)
* #id → 0,1,0,0 (ID)
* style="" → 1,0,0,0 (inline)
*
* p.class → 0,0,1,1 (element + class)
* div p → 0,0,0,2 (2 elements)
* .nav .link → 0,0,2,0 (2 classes)
* #header .nav a → 0,1,1,1 (ID + class + element)
* #header #nav → 0,2,0,0 (2 IDs)
*/
/* Which color wins? */
p { color: blue; } /* 0,0,0,1 */
.text { color: green; } /* 0,0,1,0 — wins over p */
#main { color: red; } /* 0,1,0,0 — wins over .text */
/* inline style="color: orange" — wins over #main */
/* !important — overrides everything (use sparingly!) */
p { color: blue !important; } /* wins even over inline styles */
/* Specificity tie — last rule wins */
.btn { background: blue; }
.btn { background: red; } /* wins — same specificity, later in file */
/* Practical: avoid high specificity chains */
/* BAD — hard to override */
#sidebar .widget ul li a { color: blue; }
/* GOOD — low specificity, easy to override */
.sidebar-link { color: blue; }
The Cascade
The cascade determines which CSS rule applies when multiple rules conflict. It considers three factors in order:
- Origin and importance — browser defaults < user styles < author styles <
!important - Specificity — higher specificity wins
- Source order — when specificity is equal, the last rule in the file wins
/* Inheritance — some properties inherit from parent */
/* Inherited: color, font-*, line-height, text-*, visibility */
/* Not inherited: margin, padding, border, background, width, height */
body {
color: #333; /* all text inherits this color */
font-family: Arial; /* all text inherits this font */
}
/* inherit keyword — force inheritance */
.child {
border: inherit; /* inherit border from parent (not normally inherited) */
color: inherit; /* explicitly inherit color */
}
/* initial keyword — reset to browser default */
.reset {
color: initial; /* resets to browser default (usually black) */
font-size: initial; /* resets to browser default (usually 16px) */
}
/* unset keyword — inherit if inheritable, else initial */
.unset {
color: unset; /* inherits (color is inheritable) */
margin: unset; /* initial (margin is not inheritable) */
}
/* revert keyword — reset to browser stylesheet value */
.revert {
all: revert; /* reset ALL properties to browser defaults */
}
/* Specificity best practices */
/* 1. Keep specificity low — use classes, not IDs */
/* 2. Avoid !important — it breaks the cascade */
/* 3. Use :is() and :where() for complex selectors */
/* :is() — matches any selector in list, takes highest specificity */
:is(h1, h2, h3) { margin-top: 0; }
/* :where() — same but ZERO specificity (easy to override) */
:where(h1, h2, h3) { margin-top: 0; }