Command Palette

Search for a command to run...

Hectal
PHASE 2Beginner ~22 min· topic 1 of 5

Topic 2.1

The Cascade

In one line

When several declarations try to set the same property on the same element, the cascade picks exactly one winner by comparing, in order: origin and importance, inline style, cascade layer, specificity, and order of appearance.

Think of it like this

Three people tell you what to wear today. Your school's rule says "uniform", your parent says "take a jacket", your friend says "wear the red cap". You don't wear everything at once: for each item (shirt, jacket, cap) you follow a fixed order of who to listen to first. The cascade is the browser's fixed order of who to listen to, applied to each property (colour, size, margin…) of each element separately.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Declaration
One property: value pair, like color: red;.
Competing declarations
Several declarations that try to set the same property on the same element.
Cascade
The browser's fixed set of steps for choosing one winner among competing declarations.
Origin
Where a style came from: the browser's defaults (user-agent), the person browsing (user), or the website (author).
User-agent stylesheet
The browser's built-in default styles, like blue underlined links and big bold headings.
Inline style
CSS written in an element's style attribute: <p style="color: red">.
Specificity
A score for how precisely a selector points at an element. More precise selectors win ties.
Order of appearance
Where a declaration sits in the page. When everything else ties, the later one wins.
Cascaded value
The single value the cascade picked for one property of one element.

Step by step

01Collect every declaration that matches

Take one element, say a paragraph with class="note" and id="tip", and one property, color. The browser gathers every declaration for color whose selector matches this paragraph, from every stylesheet, plus any style attribute.

Here three rules match. Without the cascade, the browser couldn't decide which colour to paint.

style.csswhole filecss
#tip  { color: crimson; }
.note { color: seagreen; }
p     { color: steelblue; }

02Compare origin and importance

All three come from the author origin (your stylesheet) and none uses !important, so they tie at this step. A declaration from the browser's default stylesheet (for example the blue colour of links) would already have lost here, because normal author styles beat normal user-agent styles.

03Check for inline styles and layers

None of the three is in a style attribute, and none is inside an @layer block, so they tie again. If the paragraph had style="color: purple", purple would win right here, and specificity would never be looked at.

04Compare specificity

Now the selectors are compared. #tip contains an ID, .note a class, p only a type. The ID selector is the most specific, so color: crimson wins, even though it is written first in the file.

That surprises many beginners: order only decides when specificity ties.

05If still tied, the last one wins

If two rules had the same specificity, say two .note rules, the one written later would win. The browser reads the page from top to bottom, and the later declaration overrides the earlier one.

style.csswhole filecss
.note { color: gray; }
.note { color: navy; }   /* same specificity, later: navy wins */
If still tied, the last one winsdiagram
Rendering diagram…

06No declaration at all? Defaulting

If no declaration sets the property, there is nothing to choose. The browser then defaults the value: inherited properties such as color copy the parent's value, and the rest (such as border) use their initial value. You'll learn this in Topic 2.3.

Try it yourself

  1. 1

    Predict, then move a rule

    In the first example, predict what happens if you move the #tip rule to the very end of the CSS. Write your guess down, then try it. (Paragraph 1 stays crimson: specificity is checked before order.)

  2. 2

    Make two rules tie

    In the first example, change #tip to .note so there are two .note rules. Predict the colour of the first two paragraphs before you run it. Now the later rule wins.

  3. 3

    Find the loser in DevTools

    Right-click paragraph 2 of the second example's preview and choose Inspect. In the Styles pane, the .msg { color: gray } declaration is crossed out: that's DevTools telling you it lost the cascade. The winning rule is listed above it.

Code & diagrams

Three rules, one paragraph: who wins? New tab

Every paragraph is bold: the `font-weight` rule had no competitor. The colour battle is decided by specificity, not by order. `getComputedStyle` reports colours as `rgb(...)` and bold as `700`.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Paragraph 1: crimson 700
Paragraph 2: seagreen 700
Paragraph 3: steelblue 700
Origin, inline style, importance and order New tab

The CSS tab is placed in the page's head, and the `<style>` element in the HTML tab comes later in the document, so its `.late` rule wins the tie.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Link: darkorange
Paragraph 1: navy
Paragraph 2: purple
Paragraph 3: seagreen
Paragraph 4: tomato
The cascade, step by stepdiagram
Rendering diagram…

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

A rule that seems to do nothing

In the first example, add p { color: black; } at the end of the CSS and expect every paragraph to turn black.

terminal
$ the page shows
── what you'll see ──
Only paragraph 3 turns black. Paragraphs 1 and 2 stay crimson and seagreen.

Break #2

Swap the stylesheet links

In a real page, load your own style.css before a library's stylesheet: <link rel="stylesheet" href="style.css"> then <link rel="stylesheet" href="library.css">.

terminal
$ DevTools → Styles
── what you'll see ──
Your rule `.btn { background: green }` is crossed out; the library's `.btn { background: blue }` wins.

Myth vs fact

Myth

The last rule in the file always wins.

Fact

Order is the last step of the cascade. Origin and importance, inline styles, layers and specificity are all checked first.

Myth

"Cascading" means styles flow down from parents to children.

Fact

That is inheritance, a separate mechanism. The cascade picks a winner among competing declarations on one element. The two work together, but they are different steps.

Myth

A whole rule wins or loses.

Fact

The cascade runs per property. One rule can win color and lose font-size on the same element.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The full order in the CSS Cascading and Inheritance Level 5 specification, from strongest to weakest origin and importance: transitions, important user-agent, important user, important author, animations, normal author, normal user, normal user-agent. So a running CSS animation overrides your normal rules but not your !important ones, and a transition beats everything while it runs.

  • ▸

    Spec details for the steps after origin: context (inside Shadow DOM, styles from the outer page beat the component's normal styles, and the order flips for !important), then element-attached styles (the style attribute), then layers, then specificity, then order of appearance. The newest draft (Level 6) adds scope proximity for @scope between specificity and order: the rule whose scope root is closer to the element wins.

  • ▸

    Rules inside @media or @supports blocks have no extra weight. They take part in the cascade exactly like rules outside them, at the position they are written. A media query at the top of the file can lose to a plain rule further down. This is a classic responsive-design bug (Phase 9).

  • ▸

    The cascade produces the cascaded value. The browser then turns it into the specified, computed, used and finally actual value (for example 2em becomes 32px). getComputedStyle() in JavaScript returns the resolved value, which is the computed value for most properties and the used value for some, like width.

Remember this

  1. 1

    A declaration is one property: value pair, like color: red. Many declarations can target the same element and the same property: a browser default, your stylesheet, a class rule, an ID rule, a style attribute. For every element and every property, the browser collects all those competing declarations and must choose exactly one. The chosen value is called the cascaded value. The process of choosing is the cascade.

  2. 2

    Step 1 is origin and importance. An origin is where a style came from: the user-agent origin (the browser's own default stylesheet: blue links, bold headings, margins on body), the user origin (styles the person browsing set up, such as a minimum font size or a high-contrast extension) and the author origin (you, the website's developer). For normal declarations, author beats user, and user beats user-agent. Declarations marked !important flip that order (Topic 2.4 explains why).

  3. 3

    Step 2: a declaration in an element's style="..." attribute (an inline style) beats any declaration that comes from a selector in a stylesheet, as long as origin and importance are equal. Step 3 is cascade layers: rules placed in named layers with @layer are ranked by layer order, and rules in no layer at all beat every layered rule (Topic 2.5).

  4. 4

    Step 4 is specificity: a score for how precisely a selector targets the element. An ID selector (#tip) beats a class (.note), which beats a type selector (p). Specificity only matters when the earlier steps tie. Topic 2.2 shows how to score any selector.

  5. 5

    Step 5 is order of appearance: if everything above ties, the declaration that appears last in the page wins. "Last" means later in the same stylesheet, or in a stylesheet that comes later in the document (a later <link> or <style>). This is why the order of your <link> tags matters, as you saw in Topic 0.2.

  6. 6

    The cascade runs per property, not per rule. If one rule wins the color battle and another wins font-size, the element ends up with a mix of both. And if no declaration sets a property at all, the cascade has no winner: the browser then uses inheritance (the parent's value, for properties like color) or the property's initial value (its built-in default). That's Topic 2.3.

Explain it without notes

01

Name the steps of the cascade in order, and say what each one compares.

02

What is an origin? Name the three origins and how they rank for normal declarations.

03

A rule #box { color: red } is written at the top of a file and .box { color: blue } at the bottom. Both match the same element. Which colour wins and why?

04

What happens to a property that no declaration sets?

Practice

01

Write CSS for <p class="intro">Hello</p> with two rules for .intro: the first sets color: red, the second color: green. Which colour shows? Then make red win without !important and without changing the HTML.

02

Given the HTML <h1 class="title">Hi</h1> and the rules h1 { color: navy; font-size: 40px; } and .title { color: tomato; }, what colour and size does the heading get?

Trade-offs

  • ↔

    Relying on order of appearance keeps selectors short, but makes styles fragile: moving a file or a <link> changes the result. Relying on specificity is independent of order, but raises the bar for every later override. Cascade layers (Topic 2.5) give an explicit, order-independent way to rank whole groups of rules.

Done when you can

  • I can list the five steps of the cascade in order.

  • I can name the three origins and say how they rank.

  • I can predict which of several rules sets a property on an element.

  • I know the cascade works per property, not per rule.

  • I can find the winning and losing declarations in DevTools' Styles pane.