The Cascade
Understand how the browser decides which CSS rule wins when several rules target the same element, using origin, importance, specificity, and source order.
CSS stands for Cascading Style Sheets, and the word 'cascading' is not decoration — it names the exact algorithm the browser runs every time two or more rules try to style the same element the same way. Once you understand the cascade, 'why isn't my CSS applying?' stops being a mystery and becomes a four-step calculation you can do in your head.
What the cascade actually resolves
Every element on a page can be targeted by many CSS rules at once: rules you wrote, rules the browser ships with by default, and sometimes rules a user's own browser settings add. When two of those rules set the same property (say, color) on the same element, the browser needs a deterministic way to pick a winner. That process — sorting competing declarations and picking one — is the cascade.
The cascade runs through four stages, in this order, and only moves to the next stage if the previous one ends in a tie: origin and importance, then cascade layers, then specificity, then source order (appearance order in the code).
• Origin — where the rule came from (browser default, user, or author/your CSS). • Importance — whether a declaration is marked !important. • Cascade layers — an optional grouping mechanism for organizing precedence (covered in depth later). • Specificity — how precisely a selector targets the element. • Source order — when everything above ties, the last rule declared wins.
Origin: three sources of styles
Browser default styles (also called the 'user-agent stylesheet') are the baseline styles every browser applies before your CSS runs — this is why an unstyled <h1> is big and bold, and an unstyled <a> is blue and underlined. Author styles are the CSS you write and link into the page — this is almost always what determines a site's real appearance. User styles are custom stylesheets a person can configure in their own browser (for accessibility needs, for example) and normally have very low priority unless marked !important.
In practice, for 99% of your work as a developer, the competition is entirely between your own author-origin rules. Understanding origin mainly explains why your CSS overrides the browser's defaults in the first place.
Importance: !important
Appending !important to a declaration lifts it above the normal cascade — it will beat any non-important declaration from the same origin, regardless of specificity or source order. It exists mainly as an escape hatch for fixing specificity fights you cannot otherwise untangle (often in third-party CSS you don't control), not as a everyday tool. Overusing !important creates a codebase where nothing can be reliably overridden without another !important, which spirals quickly.
Rule of thumb: treat !important as a last resort. If you find yourself reaching for it often, the real fix is usually to lower the specificity of your other selectors so normal cascade rules can do their job.
Specificity and source order (previewed)
When origin and importance tie, the browser compares specificity — a score based on how a selector is written (IDs count more than classes, classes count more than elements). Specificity gets its own full lesson next, since it's the part developers misuse most often.
If specificity also ties exactly, the very last matching rule in the stylesheet (in the order the browser reads the file, top to bottom) wins. This is why the order you write CSS rules in can matter — a later rule with equal specificity silently overrides an earlier one.
Inheritance vs. the cascade
It's worth naming the difference early: the cascade decides which explicit rule wins when multiple rules target the same element directly. Inheritance is a separate mechanism where some properties (like color and font-family) pass their computed value down from parent to child automatically when no rule targets the child directly. Inheritance only kicks in when the cascade finds no explicit, higher-priority value to apply — we'll cover it fully in a later lesson.
The cascade decision order
The four stages are checked in strict order; the browser only looks at the next stage if the current one is a tie. Equal specificity + later position in the file (or a later <link>/<style> block) = that rule wins.
/* When multiple declarations target the same property on the same element,
the browser resolves the conflict in this order: */
/* 1. Origin & importance — !important wins over normal declarations */
p { color: blue !important; } /* wins over the rule below */
p { color: red; }
/* 2. Cascade layers (advanced — grouping mechanism, covered later) */
/* 3. Specificity — a more specific selector wins */
#intro { color: green; } /* wins: ID beats class */
.text { color: orange; }
/* 4. Source order — last rule wins when specificity is equal */
.text { color: purple; } /* this one wins — declared last */
.text { color: orange; }Code Examples
Author styles (yours) beat browser-default styles at the same specificity, which is why linking a stylesheet changes how plain HTML elements look.
h1 { font-size: 1.75rem;... } Even though #nav-link has a much higher specificity score than.disabled, the !important declaration in.disabled wins because importance is checked before specificity.
color: gray !important;
This is a very common real bug: two rules with the exact same selector, and the second one silently wins because it appears later in the file.
/* Browser default stylesheet (not written by you) roughly says: */
/* h1 { font-size: 2em; font-weight: bold; margin: 0.67em 0; } */
/* Your author CSS overrides it: */
h1 {
font-size: 1.75rem;
font-weight: 600;
margin: 0 0 1rem;
}#nav-link {
color: navy; /* high specificity, but... */
}
.disabled {
color: gray !important; /* !important always wins over non-important, any origin+importance tie aside */
}.card {
background: white;
}
.card {
background: whitesmoke;
}
/* Result: background is whitesmoke.
Both selectors have identical specificity (one class), so
the browser falls through to source order — the later rule wins. */The cascade decision funnel
Each stage only matters if the previous stage ended in a tie.
Competing declarations on the same property
|
v
1. Origin & Importance ---- tie? ---\
| |
2. Cascade Layers ---- tie? ---\ |
| ||
3. Specificity ---- tie? ---\ ||
| |||
4. Source Order (last one wins) <-----/||/
|
v
Winning declarationImportant Rules
!important declarations beat normal declarations regardless of specificity or order.
Higher specificity beats lower specificity, regardless of source order.
With equal specificity, the last declared rule wins.
Author CSS overrides browser default styles at equal specificity.
Avoid !important in everyday code — reach for it only to override CSS you can't otherwise edit.
Why this matters on real teams
In a codebase with hundreds of CSS rules across many files, cascade conflicts happen constantly — a component library's default styles fighting your page-specific overrides, a shared 'utility' class fighting a component class. Knowing the exact four-step resolution order lets you debug 'my style isn't showing up' in seconds using browser DevTools instead of guessing and adding !important everywhere..btn { background: blue; }.btn { background: red; }
/* Keep one rule per selector, or intentionally order overrides */ .btn { background: blue; } .btn.is-danger { background: red; }
Duplicating a selector and hoping the 'right' one wins relies on remembering file order. Use a more specific or purposeful selector instead so the intent is visible in the code..title { color: black !important; }.title { color: black; }
Reaching for !important as a first fix instead of understanding why a rule isn't applying creates specificity wars later, since only another !important can then override it.
[Predict the Output] Given these two rules applied to the same <span>, and assuming neither uses !important, which color wins? span { color: teal; } .label { color: crimson; } span { color: teal; } .label { color: crimson; } A. teal, because it was declared first B. crimson, because a class selector has higher specificity than an element selector C. It's undefined — the browser picks randomly D. Both colors apply, blended together
B. crimson, because a class selector has higher specificity than an element selector — A class selector (.label) has higher specificity than a type/element selector (span), so crimson wins regardless of the order the rules were written in. Source order only matters when specificity is tied.
Given: p { color: red; } and .intro { color: blue; } applied to <p class="intro">Hello</p>, what color is the text, and why? Then, without changing selectors, make it green using only importance.
The text is blue: .intro (one class) has higher specificity than p (one element type), so it wins the cascade regardless of source order. To force green without changing the selector, add !important: p { color: green !important; } — importance is checked before specificity, so it overrides .intro.
Compare specificity first — a class beats an element type. Then think about what beats specificity entirely.