Difficulty: Intermediate
How does CSS specificity work? How do you calculate it?
Specificity determines which CSS rule wins when multiple rules target the same element.
Calculation (A, B, C): - A: Number of ID selectors - B: Number of class selectors, attribute selectors, pseudo-classes - C: Number of element selectors, pseudo-elements
Cascade order (highest to lowest priority): 1. !important declarations 2. Inline styles (style attribute) 3. ID selectors (#id) 4. Class/attribute/pseudo-class selectors 5. Element/pseudo-element selectors 6. Universal selector (*) - zero specificity
Equal specificity: last rule in source order wins. Inheritance: some properties inherit (color, font), others don't (margin, padding).
/* (0, 0, 1) - one element */
p { color: black; }
/* (0, 1, 0) - one class */
.text { color: blue; }
/* (0, 1, 1) - one class + one element */
p.text { color: green; }
/* (1, 0, 0) - one ID */
#main { color: red; }
/* (0, 2, 1) - two classes + one element */
.container .text p { color: purple; }
/* (1, 1, 1) - one ID + one class + one element */
#main .text p { color: orange; }
/* (0, 1, 0) - one pseudo-class */
:hover { color: pink; }
/* (0, 0, 2) - one element + one pseudo-element */
p::first-line { color: gray; }
/* Winner for <p class="text" id="main">:
#main (1,0,0) beats .text (0,1,0)
beats p (0,0,1) */
Compare specificity left to right: (1,0,0) always beats (0,99,99). IDs always beat classes, classes always beat elements.
/* Cascade: same specificity, last wins */
.btn { color: red; }
.btn { color: blue; } /* blue wins */
/* Inheritance: some props inherit */
.parent {
color: navy; /* inherits to children */
font-family: sans-serif; /* inherits */
border: 1px solid; /* does NOT inherit */
padding: 1rem; /* does NOT inherit */
}
/* Force inheritance */
.child {
border: inherit; /* explicitly inherit */
}
/* Reset to default */
.reset {
color: initial; /* browser default */
color: unset; /* inherit if inheritable, initial if not */
all: unset; /* reset ALL properties */
}
/* Inherited properties:
color, font-*, text-*, line-height,
visibility, cursor, list-style
NOT inherited:
margin, padding, border, background,
width, height, display, position */
Inheritance flows from parent to child for text-related properties. Layout properties like margin and padding never inherit.
/* BAD: specificity escalation */
.nav .menu .item a { color: blue; }
.nav .menu .item a.active { color: red; }
/* Need even more specificity to override? */
#nav .menu .item a.active { color: green; }
/* This spirals out of control! */
/* GOOD: flat, low specificity */
.nav-link { color: blue; }
.nav-link--active { color: red; }
/* AVOID !important (hard to override) */
.text { color: red !important; }
/* Only way to override: */
.text { color: blue !important; } /* specificity war */
/* Acceptable uses of !important: */
/* 1. Utility classes */
.hidden { display: none !important; }
/* 2. Overriding third-party CSS */
.third-party-widget {
margin: 0 !important;
}
Keep specificity low and flat. BEM naming (.block__element--modifier) helps avoid nesting. Only use !important for utilities or third-party overrides.
Specificity, Cascade, Inheritance, !important, Specificity Calculation