skip to content

In CSS, where do declarations that are not inside any @layer rank compared to layered ones?

level: middleimportance: must knowfreq 42%

answer

  1. unlayered is not "no priority"
  2. an implicit final bucket
  3. last position means strongest
  4. layered CSS volunteers to lose
  5. reversed once !important appears

basics

~20 s

Unlayered normal declarations behave as a final, implicit layer that comes after every named layer, so they beat layered rules of any specificity. Wrapping your own CSS in a layer while a vendor stylesheet stays unlayered therefore lets the vendor win.

solid answer

~50 s

For normal declarations, anything you write outside a `@layer` block acts as if it were in one last, implicit layer that sits after every declared layer. So unlayered CSS wins against layered CSS, no matter how specific the layered selector was. That trips people up in exactly one situation, and it is the common one: you adopt layers, dutifully move your own styles into `@layer components`, and then find a third-party stylesheet you did not author — which is still unlayered — suddenly overriding you where it never did before. The fix is not to add another layer of your own, because every named layer still loses to unlayered styles; it is to bring the vendor CSS into an early layer, or leave your own overrides unlayered on purpose. Note this ranking only applies to normal declarations — `!important` reverses it.

code

css · 5 lines
css
@layer components {
  #sidebar .card .title { color: red; }
}

.title { color: blue; }

go deeper

for a junior

Remember the direction: CSS written outside any layer wins over CSS inside a layer. Say it plainly rather than guessing from specificity.

for a middle

Explain it as an implicit final layer and predict the winner in a two-rule snippet. Be able to say why the spec made unlayered strongest — incremental adoption safety.

for a senior

Walk through the third-party-stylesheet scenario end to end: the symptom, why adding another layer fails, and the @import ... layer() fix instead of an !important patch.

for a principal

Own the codebase policy: either everything including vendor CSS is layered, or unlayered is a deliberately reserved escape hatch. Explain why a half-migrated stylesheet is the state that actually causes incidents.

## The rule Every normal (non-`!important`) author declaration that is *not* inside a `@layer` block is treated as belonging to a single implicit layer that is ordered **last**, after all named and anonymous layers. Last means strongest for normal declarations, so unlayered CSS beats layered CSS on layer order alone — specificity is never compared between them. ```css @layer components { #sidebar .card .title { color: red; } /* specificity (1,2,0) */ } .title { color: blue; } /* unlayered, (0,1,0) */ ``` The title is blue. The unlayered rule wins because it is effectively in the final layer, and the (1,2,0) selector in `components` is never even weighed against it. ## Why the spec chose this It makes adoption incremental and safe. If you have an existing stylesheet and start introducing layers for new architecture, the pre-existing unlayered CSS keeps behaving the way it always did — nothing you move into a layer can silently start beating the old code, so a partial migration cannot break the page from the layered side. Layers are opt-in *demotion*: the moment you put something in a layer, you volunteer it to lose against anything unlayered. ## The failure mode interviewers are probing The question is usually asked with a third-party stylesheet in the story, because that is where the model breaks people's intuition: ```css /* your file */ @layer components { .datepicker { border-radius: 0; } } /* vendor.css, loaded normally, no layers */ .datepicker { border-radius: 8px; } ``` You wrote the more deliberate rule, you may even have a more specific selector, and you still lose — because the vendor sheet is unlayered and yours is not. Adding `@layer overrides` after `components` does not help either: *every* named layer is below unlayered. There are two correct moves: 1. **Pull the vendor stylesheet into an early layer**, so it participates in the ordering you control: ```css @layer vendor, components; @import url("vendor.css") layer(vendor); ``` 2. **Leave your own overrides unlayered** deliberately, accepting that unlayered CSS is the top bucket and reserving it for the few rules that must always win. Option 1 is what most design systems do, because it keeps the "everything is in a layer" invariant and makes the override order legible in one statement. ## The `!important` inversion This ranking describes normal declarations only. Among `!important` author declarations the whole layer order flips, and the unlayered group becomes the **weakest** rather than the strongest. So `!important` on an unlayered rule is not the trump card people expect once layers are in play: an `!important` declaration in a named layer beats it. ## How to reason about it in an interview A clean mental model is one ordered list per element, built like this: `[first layer] … [last layer] [unlayered]`, with later beating earlier for normal declarations. Then, separately, the important list is the same sequence read backwards with unlayered at the bottom. If you can draw that list, every question of this shape becomes arithmetic rather than intuition. ## Diagnosing it in practice In browser devtools, an overridden declaration is struck through and the winning rule is shown above it, with layered rules grouped under their layer name — so the tell for this bug is seeing your carefully written layered rule crossed out by a plain-looking selector that would obviously have lost before layers existed. The instinct to reach for `!important` at that moment is exactly wrong; the fix is a layer-order fix. ## Anonymous layers count too A bare `@layer { ... }` block with no name is still a layer, so its rules are also below unlayered CSS. Being unnamed does not make them unlayered — that distinction matters when you inherit a codebase that used anonymous layers for one-off blocks.

  • You put your CSS in a layer and a third-party sheet started overriding you — what do you change?
    Bring the third-party sheet into a layer you control and order it first, typically with `@import url("vendor.css") layer(vendor);` and a `@layer vendor, components;` statement at the top. Adding another layer of your own would not help, because every named layer ranks below unlayered CSS. Reaching for `!important` would work but re-creates the problem layers were meant to remove.
  • Does an anonymous @layer block count as unlayered?
    No. `@layer { ... }` creates a real layer that simply has no name, so it takes a position in the layer order and ranks below unlayered styles like any other layer. The only thing it loses by being anonymous is the ability to be referenced or reopened later.
  • Does the unlayered group still rank highest for !important declarations?
    No — it becomes the lowest-priority group among important author declarations. The layer order inverts for `!important`, so an important declaration inside a named layer beats an important unlayered one, which is the opposite of the normal-declaration behaviour.

saying these in an interview costs you the question

  • Says unlayered styles are the weakest because they have no layer
  • Thinks adding one more named layer can beat unlayered CSS
  • Assumes higher specificity in a layer beats an unlayered rule
  • Claims unlayered and anonymous layers are the same thing
  • Believes the unlayered group is strongest for !important too

context