Now Reading:

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
_10
import './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:

Playground
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.

Stay ahead of the pack 🐶

Join the newsletter to get the latest articles and expert advice directly to your inbox.
Totally free, no spam and you can unsubscribe anytime you want!

  • Expert Tips
  • No Spam
  • Latest Updates

I'll never share any of your information with a third party. That's a promise.

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

DANNY

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.

1) What’s the main advantage of using CSS Layers?
file under:
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?

D is for danny

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.

Gobacktothetop

Made with 🥰 in 🏴󠁧󠁢󠁥󠁮󠁧󠁿

©2025 All rights reserved.