Most 'my CSS doesn't work' moments are the cascade doing exactly what it's specified to do.
When several declarations set the same property on an element, the cascade decides which wins, checking in order:
- Origin and importance: author styles beat browser defaults;
!importantdeclarations beat normal ones. - Cascade layers (
@layer): later layers beat earlier ones; covered in an advanced lesson. - Specificity: the more specific selector wins.
- Order: if all else is equal, the declaration that comes last wins.
Specificity is compared as three numbers (A, B, C): A counts ids, B counts classes, attributes and pseudo-classes, C counts type selectors and pseudo-elements. #nav .link is (1,1,0) and beats .menu .link:hover at (0,3,0), because one id outranks any number of classes. Inline style attributes beat any selector. The universal selector * and combinators add nothing.
Inheritance is separate: some properties, mostly text-related ones like color, font-family, font-size, line-height and visibility, pass from parent to child automatically. Box properties like margin, border, width and background don't. Any property can be forced with the keywords inherit, initial, unset or revert.
An inherited value always loses to any rule that targets the element directly, however unspecific. That's why body { color: gray } doesn't color links: the browser stylesheet targets a directly.
Treat !important as a last resort. It escalates fights instead of ending them; keep specificity low and flat instead.
Example
/* <p id="intro" class="lead">Hello <a href="#">link</a></p> */
p { color: black; } /* (0,0,1) */
.lead { color: green; } /* (0,1,0) beats p */
#intro { color: purple; } /* (1,0,0) beats .lead -> text is purple */
p.lead { color: orange; } /* (0,1,1) still loses to the id */
body { font-family: Georgia, serif; } /* inherited by p and a */
.lead { border: 1px solid; } /* NOT inherited by the link */
a { color: inherit; } /* opt in: link takes the p's purple */Remember
- Order of checks: importance, layer, specificity, then source order
- Specificity = (ids, classes/attrs/pseudo-classes, types)
- Text properties inherit; box properties don't
- A direct rule always beats an inherited value
Watch out for
- Reaching for !important instead of fixing specificity.