Section 1 · The Cascade, for Real
How the Browser Picks a Winner
14 min3 min read
Lesson at a glance
Explain the order in which the browser resolves competing declarations, so you can predict which rule wins before you open DevTools.
No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.
Every CSS bug that makes you say “but I wrote that rule” has the same root cause: more than one declaration wanted the same property on the same element, and the browser picked a different one than you did. The browser isn’t being random. It runs a fixed sorting algorithm called the cascade, and once you can run it in your head, CSS stops feeling like whack-a-mole.
This course teaches CSS from the browser’s side. You’ll learn what each modern feature does, and you’ll also learn why the browser behaves the way it does, because that’s what lets you predict the result before you reload.
The page you’ll build
All course long you’ll refine one real page: the schedule for Waypoint Conf 2026, a two-day front-end conference. It has a sticky header, a filter bar with track checkboxes, session cards (time, title, speaker, room, track badge), a speaker grid with photos, and a dark mode. It starts as plain, slightly broken CSS. By the end it uses layers, container queries, oklch() colors, view transitions and an architecture a team of five could share.
Here is the first conflict you’ll meet on it:
<article class="session" id="keynote">
<h2 class="session-title">Keynote: The Platform Is the Framework</h2>
</article>#keynote h2 { color: #6d28d9; }
.session .session-title { color: #1f2937; }The second rule comes later, so many people expect the title to be dark grey. It’s purple. To see why, you need the sorting order.
The cascade, step by step
When several declarations target the same property on the same element, the browser sorts them by these criteria, in order, and stops at the first one that separates them:
- Origin and importance. Declarations come from the browser’s default stylesheet (user-agent), the user (accessibility settings, extensions) or you (author). Normal author rules beat browser defaults.
!importantflips the order, so a user’s important rule beats yours. That’s deliberate: someone who needs large text must be able to override your design. - Inline styles. A
style="…"attribute beats any selector in a stylesheet. (The spec also has a step just before this one for Shadow DOM encapsulation; it only matters once you build web components.) - Cascade layers. Rules in later-declared
@layers beat rules in earlier ones, regardless of specificity. You’ll use this in Cascade Layers with @layer. - Specificity. How precisely the selector targets the element. IDs beat classes, classes beat element types.
- Order of appearance. If everything above ties, the declaration that appears last wins.
Back to the keynote: both rules are normal author styles, neither is inline, neither is in a layer. Step 4 decides it. #keynote h2 contains an ID, .session .session-title contains only classes, and one ID outranks any number of classes. Purple wins, and order never gets a vote.
When nobody wins
Sometimes no declaration targets a property at all. The browser still needs a value, so it defaults: inherited properties such as color, font-family and line-height copy the parent’s value, and non-inherited properties such as border, padding and background-color get their initial value. That’s why setting font-family on body styles the whole page, while setting padding on body pads only the body.
The next lesson takes step 4 apart: how specificity is calculated, why one ID can wreck a component library, and how :is() and :where() let you choose exactly how much weight a selector carries.
Key takeaways
- The cascade sorts competing declarations by origin and importance, then inline styles, then layers, then specificity, and only then by source order.
- Source order is the last tie-breaker, not the first, so moving a rule down the file fixes far fewer bugs than people expect.
- When no declaration targets a property, the browser falls back to inheritance for inherited properties and to the initial value for the rest.
!importantreverses the origin order: a user’s important rule beats an author’s important rule.