The CSS Cascade
How browsers resolve conflicting styles
What is the Cascade?
The "C" in CSS stands for Cascading. When multiple CSS rules target the same element with conflicting properties, the browser must decide which rule wins. This resolution algorithm is the cascade.
The Cascade Algorithm (simplified): ──────────────────────────────────── 1. Origin & Importance (author vs user vs browser) 2. Specificity (how targeted is the selector?) 3. Source Order (which rule comes last?) ──────────────────────────────────── Higher number = lower priority (tiebreaker)
Specificity
Specificity is a weight that determines which CSS rule takes precedence. It is calculated as a tuple of three numbers: (IDs, Classes, Elements).
/* Specificity: (0, 0, 1) — one element */
p { color: black; }
/* Specificity: (0, 1, 0) — one class */
.highlight { color: blue; }
/* Specificity: (1, 0, 0) — one ID */
#title { color: red; }
/* Specificity: (0, 1, 1) — one class + one element */
p.highlight { color: green; }
/* Specificity: (1, 1, 1) — one ID + one class + one element */
div#main .text { color: purple; }Specificity Comparison: ──────────────────────────── p → (0, 0, 1) .highlight → (0, 1, 0) ← wins over p #title → (1, 0, 0) ← wins over .highlight p.highlight → (0, 1, 1) ← wins over .highlight inline style → (1, 0, 0, 0) ← wins over everything ──────────────────────────── Higher left digit always wins.
Inheritance
Some CSS properties are inherited by child elements from their parents. Typography properties like color, font-family, and line-height are inherited. Layout properties like margin, padding, and border are not.
body {
color: #333; /* Inherited by ALL descendants */
font-family: sans-serif; /* Inherited */
line-height: 1.6; /* Inherited */
}
.card {
border: 1px solid #ddd; /* NOT inherited */
padding: 16px; /* NOT inherited */
}
/* Force inheritance */
.child {
border: inherit; /* Explicitly inherit from parent */
}Source Order
When two rules have the same specificity, the last one declared wins. This is why the order of your CSS files and rules matters.
/* Same specificity (0, 1, 0) */
.text { color: blue; }
.text { color: red; }
/* Result: red wins (declared last) */
/* File order matters too */
/* base.css loaded first, then theme.css */
/* theme.css overrides base.css for same specificity */!important
The !important annotation overrides all specificity rules. It should be used sparingly — it makes CSS harder to maintain and debug.
p { color: black; }
.highlight { color: blue; }
#title { color: red; }
/* This wins over everything above */
p { color: green !important; }
/* Only another !important with higher specificity can override it */
.highlight { color: purple !important; } /* Wins over p !important */Best practice
Avoid !important in your regular styles. It is acceptable in utility classes (like .hidden { display: none !important }) and for overriding third-party CSS you cannot modify.
Summary
Specificity determines the winner
IDs beat classes, classes beat elements. When specificity ties, source order is the tiebreaker.
Inheritance reduces repetition
Set typography on body and let it cascade down. Only override where needed.
Keep specificity low
Use classes instead of IDs. Avoid deeply nested selectors. This makes your CSS easier to maintain and override.