Organizing CSS with cascade layers

Organize CSS without specificity wars

Old approach: stack selectors, raise specificity, throw !important. Cascade layers let you declare a priority order once, then write clean CSS.

Old way Specificity stacking
/* Base styles */body {  margin: 0;  font-family: sans-serif;}/* Components - start simple */.card {  padding: 1rem;  background: white;  border: 1px solid #ccc;}.card h2 {  margin-top: 0;  color: #333;}.card.highlight {  background: yellow;}.card.highlight h2 {  color: red;}/* Utilities - need more specificity or !important to override components */.mt-4 {  margin-top: 1rem !important;}.mt-2 {  margin-top: 0.5rem !important;}/* If utilities still don't win, add more specificity */.sidebar .card .mt-4 {  margin-top: 0.5rem !important;}/* specificity wars: stacking selectors, fighting !important */
Modern
@layer order
@layer reset, base, components, utilities;@layer reset {  * { margin: 0; padding: 0; }}@layer base {  body {    font-family: sans-serif;  }}@layer components {  .card {    padding: 1rem;    background: white;    border: 1px solid #ccc;  }  .card h2 {    margin-top: 0;    color: #333;  }  .card.highlight {    background: yellow;  }  .card.highlight h2 {    color: red;  }}@layer utilities {  .mt-4 { margin-top: 1rem; }  .mt-2 { margin-top: 0.5rem; }}/* layers handle priority, no !important needed */
Widely available Since 2022 95% global usage

This feature is well established and works across many devices and browser versions. It has been available across browsers since 2022.

Safe to use without fallbacks.

99+
97+
15.4+
99+

Order matters, not specificity

Later layers beat earlier ones. No selector stacking required. Utilities override components automatically.

No !important needed

Layer precedence handles priority. Write plain selectors. Scale without the maintenance burden.

Predictable structure

reset → base → components → utilities. Same pattern every time. Easy to onboard and maintain.

Lines Saved
N/A
Cleaner architecture
Old Approach
Specificity wars
Selector stacking, !important
Modern Approach
@layer order
Declared priority

How it works

The old way required managing specificity: make selectors more specific to override (e.g., .page .card .title), or throw !important to force wins. This leads to specificity wars where each new override needs higher specificity, making the codebase hard to maintain.

@layer reset, base, components, utilities declares your layer order upfront. Styles in utilities beat components beat base beat reset, regardless of selector specificity. Write plain classes and single selectors. No long chains needed.

This pattern scales. Add utility classes without fighting existing component styles. Refactor old CSS into separate layers. The layer order is explicit and obvious to anyone reading the code.

ESC