Cascade Layers

Organize Rules by Priority — Without `!important`

Cascade Layers

`@layer` groups rules into named priority bands. A rule in a later layer beats a rule in an earlier layer — regardless of specificity.

3 min read Level 2/5 #css#layers#cascade
What you'll learn
  • Declare and order layers
  • Move third-party CSS into a low-priority layer
  • Stop fighting specificity

@layer groups rules into named priority bands. Rules in a later layer always beat rules in an earlier layer, regardless of specificity. Inside a layer, specificity rules normally.

Declare Layers In Order

@layer reset, base, components, utilities;

Order matters. Later in the list = higher priority.

Put Rules In Layers

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

@layer base {
  body { font-family: system-ui; line-height: 1.5; }
  a    { color: var(--brand); }
}

@layer components {
  .btn { padding: 0.5rem 1rem; border-radius: 6px; }
}

@layer utilities {
  .text-center { text-align: center; }
  .hidden { display: none; }
}

A utility like .text-center beats a .heading rule in components, even though both are single-class selectors. Layers trump specificity.

Third-Party CSS Into a Low Layer

@import url("third-party.css") layer(vendor);
@layer vendor, base, components, utilities;

Vendor styles are now the LOWEST priority, even if they use high-specificity selectors. Your normal CSS beats them effortlessly.

Unlayered Styles

Styles NOT in any layer have priority OVER all layers. Useful for emergency overrides — but if you find yourself relying on this, your layer order is probably wrong.

When To Reach For Layers

  • Big projects with mixed sources (vendor, base, components, utilities)
  • Stop using !important to win specificity fights
  • Tailwind-style utility-first setups, where utilities should always win

For a small project with just your own CSS, layers can be overkill. Use them when complexity warrants.

Up Next

:has() — the parent selector everyone wanted for a decade.

`:has()` →