Write More Predictable CSS Using @layers
At its core, CSS has always relied on a few things to determine which style wins when multiple rules apply: source order, specificity, and importance (!important
). This system works, but it breaks down as projects scale.
CSS Layers introduce a new axis to the cascade: @layer
. You can now explicitly control the order of entire groups of styles, regardless of specificity or order in your stylesheet.
Think of it like stacking boxes:
- Each layer is a box.
- CSS rules inside the top box win over those in boxes below, even if they have lower specificity.
This makes styles more predictable, especially in large codebases or design systems.
If you’re working with component libraries, design tokens, or CSS-in-JS tools in a React project, layering lets you define things like:
- Base styles (tokens, resets) that never override your app styles.
- Theme styles that can override base styles but not your app-specific overrides.
- Component styles that sit in their own sandbox.
This structure reduces bugs and mental overhead.
Setting Up CSS Layers
#Let’s walk through a step-by-step example of how you might structure layers in a real React project using plain CSS Modules or even global styles.
Define Layers
_10/* styles.css */_10@layer reset, base, components, utilities, overrides;
This line sets up named layers and their explicit order from bottom (least priority) to top (most priority).
So:
reset
< base
< components
< utilities
< overrides
Add Styles to Layers
Now, we assign styles to those layers.
_41@layer reset {_41 *, *::before, *::after {_41 margin: 0;_41 padding: 0;_41 box-sizing: border-box;_41 }_41}_41_41@layer base {_41 body {_41 font-family: system-ui, sans-serif;_41 background-color: #fff;_41 color: #333;_41 }_41}_41_41@layer components {_41 .button {_41 padding: 0.5rem 1rem;_41 border-radius: 0.25rem;_41 border: 1px solid transparent;_41 background-color: #007bff;_41 color: white;_41 }_41}_41_41@layer utilities {_41 .text-center {_41 text-align: center;_41 }_41_41 .mt-4 {_41 margin-top: 1rem;_41 }_41}_41_41@layer overrides {_41 .button {_41 background-color: hotpink;_41 }_41}
Even though .button
appears in both the components
and overrides
layers, the one in overrides
wins, without needing to increase specificity or use !important
. Yay
Using It in React App
Let’s say you’re using create-react-app
, Vite, or Next.js. You can add a global stylesheet that imports these layers, or even better, split each layer into its own file:
_10@import './reset.css' layer(reset);_10@import './base.css' layer(base);_10@import './components.css' layer(components);_10@import './utilities.css' layer(utilities);_10@import './overrides.css' layer(overrides);
In your root layout:
_10// App.tsx or _app.tsx_10import './index.css';
And Boom! You’ve just created a clean, maintainable style architecture.
An Example With Themed Design Systems
#Imagine you’re working on a design system for a pet adoption app. You’ve got tokens for spacing, typography, and colours. Then you’ve got buttons and card components. Finally, you want consumers of your system to override styles without fighting your specificity.
This is a perfect use case for cascade layers:
_20@layer tokens {_20 :root {_20 --spacing-sm: 0.5rem;_20 --color-primary: cornflowerblue;_20 }_20}_20_20@layer components {_20 .adopt-button {_20 padding: var(--spacing-sm);_20 background-color: var(--color-primary);_20 border-radius: 0.25rem;_20 }_20}_20_20@layer consumer-overrides {_20 .adopt-button {_20 --color-primary: salmon;_20 }_20}
In practice it would look something like the example below:
import React from "react"; import "./styles.css"; import Button from "./Button"; export default function App() { return ( <div className="app"> <h1>Design System Layering</h1> <Button>Adopt a Dog 🐶</Button> </div> ); }
You get the power of theming without leaking specificity.
Top Tips
#It’s always a good to define your layer order early on using @layer name1, name2, ...
by grouping related styles together in named layers. To make things more modular, use @import
with the layer()
keyword.
Bu remember @layer
won’t fix fix bad CSS structure. It’s a tool, not a silver bullet.
Conclusion
#CSS Layers are like adding TypeScript types to your stylesheets: more structure, more predictability, less pain in the long run. For frontend engineers building complex UIs with React and design systems, they offer a powerful way to bring order to your CSS without relying on naming conventions and more !importantly, no specificity hacks.
So next time your component styles are fighting with a global reset or a rogue utility class, think @layers
.
As always, halpy coding
Reinforce Your Learning
One of the best ways to reinforce what your learning is to test yourself to solidify the knowlege in your memory.
Complete this 3 question quiz to see how much you remember.
CSS
Thanks alot for your feedback!
The insights you share really help me with improving the quality of the content here.
If there's anything you would like to add, please send a message to:
[email protected]Was this article this helpful?

About the author
Danny Engineering
A software engineer with a strong belief in human-centric design and driven by a deep empathy for users. Combining the latest technology with human values to build a better, more connected world.