CSS Cascade Layers

CSS cascade layers give you explicit control over the order of precedence between groups of styles. Instead of fighting specificity to override a third-party library or struggling with rule order, you declare named layers and decide upfront which layer wins when there is a conflict.

The Problem Cascade Layers Solve

DIAGRAM — The classic override problem:

You use a CSS library with this rule:
  .btn { background: blue; } /* specificity: 010 */

Your own style:
  .btn { background: red; }  /* specificity: 010 */

Both have the same specificity.
Order decides — and the library loads before your code.
Result: button stays blue.

Fix attempt:
  button.btn { background: red; } /* specificity: 011 — wins */
  
Later the library adds:
  .wrapper .btn { background: blue; } /* specificity: 020 — wins again! */
  
You keep bumping specificity. It never ends.
DIAGRAM — With cascade layers:

@layer base, components, utilities;

@layer base {
  .btn { background: blue; } /* in "base" layer */
}

/* Your styles in "utilities" — declared AFTER base, so they win */
@layer utilities {
  .btn { background: red; }  /* wins! Layer order trumps specificity */
}

No specificity war. The layer hierarchy is clear and permanent.

Declaring Layers

Declare the layer order at the top of your stylesheet using a single @layer statement with the layer names. The order you declare here determines which layer wins: layers declared later win over layers declared earlier.

/* Declare order first — later = higher priority */
@layer reset, base, components, utilities;
DIAGRAM — Layer priority:

@layer reset, base, components, utilities;

Priority (lowest to highest):
  reset      ← lowest (easiest to override)
  base       ← 
  components ←
  utilities  ← highest (hardest to override)

Adding Styles to a Layer

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

@layer base {
  body {
    font-family: sans-serif;
    line-height: 1.6;
    color: #333;
  }
  a { color: blue; }
}

@layer components {
  .btn {
    display: inline-block;
    padding: 10px 24px;
    background: #3498db;
    color: white;
    border-radius: 6px;
  }
  .card {
    background: white;
    border-radius: 8px;
    padding: 20px;
  }
}

@layer utilities {
  .text-red   { color: red; }
  .mt-auto    { margin-top: auto; }
  .hidden     { display: none; }
}

How Layer Priority Works

@layer reset, base, components, utilities;

@layer components {
  .btn { background: blue; } /* specificity: 010 */
}

@layer utilities {
  .btn { background: red; }  /* specificity: 010 */
}

Result: RED — because "utilities" is declared after "components"
        Layer order beats specificity!
/* Even a lower-specificity rule in a higher layer wins */
@layer components {
  .big-wrapper .side-panel .btn { background: blue; } /* 030 */
}

@layer utilities {
  .btn { background: red; } /* 010 — wins anyway! */
}

Result: RED — utilities layer wins, even with lower specificity

Unlayered Styles Always Win

Styles NOT inside any layer always win over all layered styles, regardless of specificity.

@layer utilities {
  .btn { background: red !important; }
}

/* This is outside any layer */
.btn { background: green; }

Result: GREEN — unlayered styles beat all layers
DIAGRAM — Full priority order (lowest to highest):

1. Layer "reset" styles
2. Layer "base" styles
3. Layer "components" styles
4. Layer "utilities" styles
5. Unlayered styles        ← always wins over any layer
6. !important (reversed order for !important rules)

Importing Third-Party CSS into a Layer

This is one of the most practical uses. You put a library's CSS into a low-priority layer so your styles always override it without specificity battles.

/* Put Bootstrap into a "framework" layer */
@layer framework {
  @import url("bootstrap.min.css");
}

/* Declare your app layers above "framework" */
@layer framework, app;

/* Your styles win over Bootstrap automatically */
@layer app {
  .btn { background: purple; } /* wins over Bootstrap's .btn */
}

Nested Layers

Layers can be nested inside other layers for finer organization.

@layer components {
  @layer buttons {
    .btn { padding: 10px 20px; }
  }

  @layer cards {
    .card { border-radius: 8px; }
  }
}

/* Reference nested layers with dot notation */
@layer components.buttons {
  .btn-sm { padding: 6px 12px; }
}

Anonymous Layers

You can create a layer without naming it. Anonymous layers cannot be referenced again — they are useful for one-time imports of third-party code.

@layer {
  /* These styles are in an anonymous layer */
  /* They cannot be added to later */
  .legacy-class { color: gray; }
}

Layers with @import

/* Import and assign to a layer in one line */
@import url("normalize.css") layer(reset);
@import url("theme.css")     layer(base);

A Complete Layer Architecture

/* 1. Declare all layers in order (lowest priority first) */
@layer reset, tokens, base, layout, components, utilities;

/* 2. Reset browser defaults */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; margin: 0; }
}

/* 3. Design tokens (CSS variables) */
@layer tokens {
  :root {
    --color-primary: #3498db;
    --space-md: 16px;
  }
}

/* 4. Base element styles */
@layer base {
  body { font-family: sans-serif; }
  h1   { font-size: 2rem; }
  a    { color: var(--color-primary); }
}

/* 5. Page-level layout */
@layer layout {
  .container  { max-width: 1200px; margin-inline: auto; }
  .grid-3col  { display: grid; grid-template-columns: repeat(3, 1fr); }
}

/* 6. UI components */
@layer components {
  .btn  { padding: var(--space-md); background: var(--color-primary); }
  .card { padding: var(--space-md); border-radius: 8px; }
}

/* 7. Utility classes — override anything */
@layer utilities {
  .hidden { display: none; }
  .flex   { display: flex; }
}

Browser Support

Cascade layers are supported in all modern browsers — Chrome 99+, Firefox 97+, Safari 15.4+. For older browser support, a PostCSS plugin can polyfill the behavior.

When to Use Layers

SituationUse Layers?
Using a third-party CSS libraryYes — put library in a low-priority layer
Large team projectYes — layers enforce consistent override rules
Design systemYes — separate tokens, base, and components
Small personal projectOptional — overkill for simple sites

Cascade layers make CSS architecture explicit and predictable. Define the hierarchy once, follow it consistently, and the specificity wars that plague large stylesheets become a thing of the past.

Leave a Comment

Your email address will not be published. Required fields are marked *