Skip to content

CSS cascade layers

Rank declarations by origin and importance, then layer, specificity, and source order; use named layers before selector fights begin.

Predict first

Before you read: predict

The proctor console uses this candidate CSS for one status marker.

@layer vendor, components;
@layer vendor { #panel .status { color: red; } }
@layer components { .status { color: purple; } }
.status { color: black; }
@layer vendor { .status { color: orange; } }

The marker is <div id="panel"><span class="status">Review</span></div>.

Wrong or E → FULL. C with a vague why → TARGETED on steps 2–6. FAST needs layer-before-specificity and specificity-before-source-order.

What computed colour does Chromium render?

Pick one

The 30-second version

The cascade first filters declarations by relevance, then ranks origin and importance. Inside the same origin and importance, normal unlayered declarations beat normal layered ones; later named layers beat earlier ones. Important declarations reverse that layer order. Only then compare specificity, then source order. Declare layers up front so vendor CSS stays below components without escalating selectors.

Rank declarations by origin and importance, then layer, specificity, and source order; use named layers before selector fights begin.

How it works

Step 1 of 10

Match first. The browser considers only relevant declarations: a matching selector, applicable media condition, and supported property.
In the kitchen
  • only swatches selected for the garment matter → matching, applicable declarations (step 1)

Analogy: Fabric swatches on a worktable

The selected image shows a person laying an ochre swatch on stacked blue and teal fabric, beside a smaller stack, scissors and a ruler. An opaque top swatch hides a lower one even when the lower fabric has a more intricate pattern. The visible surface depends on position before pattern detail.

In the fabric scene In the cascade
only swatches selected for the garment matter matching, applicable declarations (step 1)
a top opaque swatch covers a lower swatch the higher normal layer wins (step 5)
intricate pattern detail cannot show through that cover specificity cannot cross layer rank (step 7)
moving the stack changes the visible fabric changing declared layer order changes priority (steps 4–5)
lifting the top swatch reveals the next surface removing a layer's value exposes lower layers (step 10)

In real terms: layers decide whole groups before selectors compete. A vendor ID selector remains below a component rule when both are normal and the component layer ranks higher.

Breaks down when: origin or importance differs. Fabric has no equivalent of important-layer reversal, animation origin, or source-order ties; those need the explicit cascade rules.

Contrasting case: two equal component selectors in the same layer. No layer decision remains, so the later source declaration sets the value.

Examples, run for real

4.1 Keep the policy visible

An ExamHall screen can declare foundation, widgets, and screen before the corresponding rules arrive. A normal screen rule then outranks a normal widget rule even if the widget selector contains an ID. That lets a component keep a plain selector and makes the intended boundary reviewable in the entry stylesheet.

The laboratory fixture changes only the declaration rank in a neutral layer set. It confirms both directions: later named layers have the higher normal rank, while earlier named layers have the higher important rank. This teaches the ordering rule without reusing a served layer name, selector, colour, or answer.

4.2 Compare author positions deliberately

A separate Chromium fixture gives a neutral badge inline opacity:0.75 and a paused animation with both endpoints at opacity:0.25. The measured line is animation opacity: 0.25; animation disabled: 0.75. Disabling only the animation exposes the normal inline value, demonstrating the positions independently of selector weight.

Element-attached styles and important author declarations also have their own positions. Treat a layer as a comparison that begins only after origin and importance leave declarations tied. A component should therefore solve ordinary vendor conflicts with declared layers before raising selector weight or adding !important.

4.3 Use source order only after a real tie

Two declarations can still tie after origin, importance, layer, and selector weight agree. In that narrow case, the later declaration wins. Put such local adjustments beside the owning component; moving text later in a different layer does not create the same comparison.

Picture it

Concept illustration for this lesson.
An illustration to help it stick. The mechanism is in the sections above.

Try it

Answer first, then check. Nothing is saved.

Question 1 of 6

This one component layer styles a checkout button.

@layer components {
  .shell .pay { color: green; } button.pay { color: blue; } .pay { color: orange; }
}

What computed colour does <div class="shell"><button class="pay">Pay</button></div> render?

Pick one

Question 2 of 6

This declared stylesheet has a vendor layer and a component layer.

@layer vendor, components;
@layer components { .tag { color: green; } }
@layer vendor { #box .tag { color: orange; } .tag { color: blue; } }

What computed colour does .tag render?

Pick one

Question 3 of 6

This marker has a normal red stylesheet rule, an inline green normal author value, and a paused animation whose start and end both set blue.

.notice { color: red; }
@keyframes tint { from { color: blue; } to { color: blue; } }
.notice { animation: tint 1s steps(1, end) paused; }

The marker is <span class="notice" style="color: green">Notice</span>.

What computed colour does it render?

Pick one

Question 4 of 6

All four declarations below are important.

@layer alpha, beta, gamma;
@layer alpha { .status { color: teal !important; } }
@layer beta { #panel .status { color: orange !important; } }
@layer gamma { .status { color: purple !important; } }
.status { color: black !important; }

The marker is <div id="panel"><span class="status">Review</span></div>.

What computed colour does the status marker render?

Pick one

Question 5 of 6

The imported vendor status is the reference colour.

/* The local fixture import resolves to: #receipt .status { color: green; } */
@import url("data:text/css,%23receipt%20.status%20%7B%20color%3A%20green%3B%20%7D") layer(theme);
@layer components, theme;
@layer components { .status { color: purple; } }

The marker is <div id="receipt"><div class="status">Status</div></div>.

Which patch makes the checkout marker render that reference colour?

Pick one

Question 6 of 6

A checkout’s status variant should display the same colour it has when the final colour rule is absent.

body { color: green; }
@layer base, components, overrides;
@layer base { .status { color: red; } }
@layer components { .status { color: blue; } }
@layer overrides {
  .status { color: orange; }
  .status.variant { /* insert one candidate declaration here */ }
}

The marker is <div class="status variant">status</div>.

Which declaration belongs in .variant?

Pick one

Go deeper

Pro tips
  1. Read a conflict's layer before its selector. Chromium's Styles pane groups matched rules under their layer names; check which layer each competing declaration sits in before raising selector weight or adding !important.
  2. Keep exception rules visible beside their layer policy. When a declaration must be important, document why it bypasses the normal override path and inspect its computed value in a neutral diagnostic fixture before relying on it.
Source

Checked against the tools and docs as of 2026-09-30.