Skip to content
AgileLogics
7 min read

Cascade Layers

Prerequisites: The cascade in depth

Cascade layers (@layer) let you group styles and decide which group wins — regardless of specificity.

@layer reset, base, components, utilities;

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  body { margin: 0; }
}

@layer base {
  a { color: #0b57d0; }
  h1, h2, h3 { line-height: 1.2; }
}

@layer components {
  .card a { color: inherit; }
}

@layer utilities {
  .text-red { color: #c62828; }
}
  • The first statement fixes the order: later layers win. Here utilities beats components, which beats base.
  • Inside a layer, normal specificity and order apply.
  • Unlayered styles (outside any @layer) beat all layers.

Specificity doesn't cross layers

<style>
  @layer base, components;
  @layer components {
    .button { color: rgb(0, 128, 0); }
  }
  @layer base {
    #main nav a.button.primary { color: rgb(255, 0, 0); }
  }
  .note { color: rgb(0, 0, 255); }
  @layer components {
    p.note.important { color: rgb(255, 165, 0); }
  }
</style>
<div id="main"><nav><a class="button primary" href="/">Go</a></nav></div>
<p class="note important">Note</p>
<script>
  console.log("button:", getComputedStyle(document.querySelector(".button")).color);
  console.log("note:", getComputedStyle(document.querySelector(".note")).color);
</script>
button: rgb(0, 128, 0)
note: rgb(0, 0, 255)
  • The button is green: the components layer outranks base, even though the base selector has an id and three classes.
  • The note is blue: the unlayered .note beats the layered p.note.important.

Layering third-party CSS

@import url("vendor/bootstrap.css") layer(vendor);
@layer vendor, app;

Wrapping a framework in a low layer means your own styles override it without specificity battles.

!important reverses layer order

Important declarations in earlier layers beat important ones in later layers (just like origins). This lets a reset layer protect rules — for example, reduced-motion overrides — with !important.

Nested layers and revert-layer

@layer components {
  @layer button, card;
}
@layer components.button {
  .btn { padding: 0.5rem 1rem; }
}
.special-btn { padding: revert-layer; }

revert-layer rolls a property back to what the previous layers set.

Cascade layers are supported in all major browsers since 2022 (Chrome and Edge 99, Firefox 97, Safari 15.4). Tailwind CSS v4 uses them for its theme, base, components, and utilities layers.

Practice

A site imports library.css whose .btn rule has high specificity. Reorganize so your simple .btn rule wins, without !important or extra selectors.

Show solution
@layer library, app;

@import url("library.css") layer(library);

@layer app {
  .btn { border-radius: 999px; }
}

Even unlayered, your .btn would beat anything in the library layer. (Note that @import must come before other rules except @layer statements and @charset.)