Lesson 1 of 30
The cascade normally resolves conflicts by specificity and source order, which is why large codebases end up in specificity arms races. @layer lets you sidestep that fight by declaring priority explicitly.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
`@layer reset, components;` is declared. `.button { color: blue; }` is written inside `reset`, and `.button { color: red; }` is written inside `components`, with identical specificity. Which color wins?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Without layers, when two rules target the same element, the browser resolves the conflict with a fixed algorithm: origin and importance first, then specificity (how precise the selector is — an ID beats a class, a class beats an element), then source order (later wins ties). That's why large codebases drift into a specificity arms race — someone adds !important, someone else adds an extra class to out-specify it, and six months later nobody can predict which rule actually wins.
@layer adds a second axis to that resolution, ahead of specificity. You declare a set of named layers up front, in the priority order you want:
@layer reset, base, components, utilities;
Rules inside a later-declared layer always beat rules in an earlier layer, no matter how specific either selector is. Specificity only gets consulted to break ties within the same layer. This turns "which rule wins" from an emergent accident of selector-writing into something you state explicitly at the top of your stylesheet.
@layer reset, components;
@layer reset {
.button { color: blue; }
}
@layer components {
.button { color: red; }
}
Two rules target the same .button, with identical specificity — an unresolved conflict.
components was declared after reset, so .button renders red — even though both selectors have identical specificity. That's the whole point: instead of relying on load order or padding selectors with extra classes, the layer order itself is the tiebreaker, and it reads top-to-bottom in the stylesheet as documentation of intent.
The one counterintuitive part: unlayered styles always beat layered ones, regardless of layer order. So a layered .button { color: red } loses to an unlayered #id { color: blue }, and it also loses to an unlayered .button { color: green } with the exact same selector — being inside any layer is a strictly lower priority than not being in one at all.
@layer reset, base, components; statement (even with empty bodies) fixes the order for the whole document — later @layer components { ... } blocks just add rules to an already-positioned layer, they don't move it.!important flips the layer order. Inside layered styles, an !important declaration in an earlier layer beats one in a later layer — the priority order inverts for the important flag specifically, which is easy to forget mid-debug.@layer only changes what happens between layers.@layer and fall back to normal cascade rules — there's no @supports fallback needed since it degrades gracefully rather than breaking."How would you stop a component library's CSS from fighting your app's overrides without reaching for !important?" is a real question that tests whether a candidate knows cascade layers exist as the intended, purpose-built answer to a problem teams have historically hacked around with specificity tricks.