Skip to main
An image of the PostCSS Cascade Layers Plugin NPM package README
including the version number, installation command, and a description of the

Cascade Layers – There’s a Polyfill for That!

Cascade layers are an exciting new addition to the CSS specification. A newly released polyfill now provides even greater browser support for the feature.

A tweet of a photo of a talk given at the CSS Day conference by
    Bramus Van Damme where he is standing in front of a slide
    that shows how the cascade layers polyfill transforms CSS.

This year, a number of new additions to the CSS specification have been announced. Cascade layers are one of the most anticipated – and rightfully so.

If you have ever struggled with conflicting CSS selectors, tried making sense of CSS from various sources, or used !important one too many times, you are either really excited about layers or you are about to be.

In a nutshell, layers allow us to define explicit containers of specificity so that we have precise control over CSS styles and their priority without relying on confusing and conflicting hacks.

If you are new to cascade layers, “A Complete Guide to CSS Cascade Layers” by Miriam Suzanne on CSS-Tricks is a must-read.

This description from W3 also sums up the power of layers especially well:

“Authors can create layers to represent element defaults, third-party libraries, themes, components, overrides, and other styling concerns – and are able to re-order the cascade of layers in an explicit way, without altering selectors or specificity within each layer, or relying on source-order to resolve conflicts across layers.”

If you want to play around with layers and see how exactly they work, check out this CodePen to see the at-rule in action.

If you’re excited to get started but are wondering which browsers actually support @layer, we have some good news.

The latest versions of Chrome, Firefox, and Safari now all support cascade layers. If you are looking for specific browsers or versions, you can see the complete browser support breakdown below from CanIUse.

Data on support for the css-cascade-layers feature across the major browsers from

Miriam Suzanne – the author of the CSS layers specification and the CSS Tricks guide shared above – also created a CodePen to quickly check if your current browser supports cascade layers:

See the Pen Does This Browser Support @layer? by @miriamsuzanne on CodePen.

And for the browsers that don’t yet support layers?

The recent retirement of IE 11 made for some great jokes and celebration, but even if you or your users aren’t using IE 11, you might still be hesitant to incorporate @layer into your CSS in case your users aren’t using the latest browser versions.

There is some more good news here as well. We at OddBird worked with the fine folks at PostCSS to build a plugin that provides a polyfill for layers. The PostCSS Cascade Layers polyfill is live now and available as an NPM package! 🚀 🎉

If you are curious about how the polyfill works exactly, let’s dive into the details.

The plugin starts by parsing a stylesheet, looking for any layer at-rules (i.e. @layer) and recording the order in which the layer was defined.

In this step, the most specific selector is also recorded and with these two elements, the plugin determines the specificity adjustment for each layer. This specificity adjustment represents the importance of the layer in relation to other layers and unlayered styles.

Next, the plugin begins the transformation of the CSS. The plugin removes the layer at-rules and gives the styles encompassed in that particular layer the appropriate specificity that was determined in the first step.

During this transformation, the plugin also applies the highest specificity to unlayered styles, i.e. styles outside of a layer since they have the highest priority.

What that looks like in practice is something like this:

target {
  color: purple;

@layer {
  target {
    color: green;

/* becomes */

target:not(#\#) {
  color: purple;

target {
  color: green;

The key principle behind the polyfill is that increasing the number of selectors is a browser-compatible way to increase specificity and importance in CSS.

The example above is fairly simple, but if your stylesheet has a number of layers and highly specific selectors, you can expect the transformation to leverage a greater number of selectors to accommodate the complexity.

The README in the GitHub repository for the polyfill illustrates this with a table:

layer specificity adjustment selector
A 0 N/A
B 3 :not(#/#):not(#/#):not(#/#)
C 6 :not(#/#):not(#/#):not(#/#):not(#/#):not(#/#):not(#/#)

The polyfill handles both named and anonymous layers as well as layers that are nested within each other.

One of the highlights of cascade layers is how this at-rule can be used in conjunction with @import to create a new layer from an input source like so:

 @import 'theme.css' layer(utilities);

The plugin also supports this feature since there is an existing PostCSS plugin for @import that you can leverage. That was an advantage of working within the PostCSS ecosystem.

So…what does the polyfill not do?

There are some expected limitations of the plugin since it is parsing a stylesheet and not running in the browser.

The two main things that the plugin does not currently handle are:

On the bright side, the plugin does look for these elements when parsing the stylesheet, and will inform authors that they are not currently supported or handled by the plugin.

These elements are best handled by polyfills in the browser, so keep your eyes on the OddBird blog to find out when a browser polyfill becomes available as well.

The PostCSS Cascade Layers plugin will run in all Node environments, and special instructions are available for: Node, PostCSS CLI, Webpack, Create React App, Gulp, and Grunt.

If you’re ready to get started, here are the first steps to get going.

Begin by installing the PostCSS Cascade Layers plugin into your project:

npm install postcss @csstools/postcss-cascade-layers --save-dev

Next, use it as a PostCSS plugin:

const postcss = require('postcss');
const postcssCascadeLayers = require('@csstools/postcss-cascade-layers');

  postcssCascadeLayers(/* pluginOptions */)
]).process(YOUR_CSS /*, processOptions */);

To learn more, check out this demo to see how the polyfill is used.

Cascade layers are a game changer, and we hope that with this new polyfill you’re excited and ready to start using them in your CSS.

Have you already started using cascade layers and/or the new polyfill? Tweet @OddBird and tell us all about it, especially if you have feedback, questions, or suggestions!

Upcoming Workshop

Mia from behind,
standing at a laptop -
speaking to a conference audience
and gesturing to one side

Cascading Style Systems

A workshop on resilient & maintainable CSS

New CSS features are shipping at an unprecedented rate – cascade layers, container queries, the :has() selector, subgrid, nesting, and so much more. It’s a good time to step back and understand how these tools fit together in a declarative system – a resilient cascade of styles.

Register for the October workshop »


Vadim Makeev


@hexagoncircle I’m convinced it’s a paradigm shift bigger than the CSS grid layout was. Yes, it was possible to limit grids to support old IE or write a fallback flexbox layout, but most people chose to wait for full support. It was more practical in many ways. That’s my…

Baldur Bjarnason


@hexagoncircle I’ve been using cascade layers with graceful degradation on a recent project. Website not app which simplifies things.

Basic approach: core CSS setting properties I know will be used so it doesn’t matter that they override the layered CSS, combined with a small piece of JS that loads…

Recent Articles

  1. A back hoe on the bank of the Suez, trying to free the Ever Given cargo ship
    Article post type

    Learn Grid Now, Container Queries Can Wait

    Take your time with new CSS, but don’t sleep on the essentials

    Several people have asked recently why container queries aren’t being used more broadly in production. But I think we underestimate the level of legacy browser support that most companies require to re-write a code-base.

    see all Article posts
  2. A clear kitchen blender filled with chopped fruit and greens
    Article post type

    Can you un-mix a mixin?

    Rethinking the CSS mixin proposal after CSS Day

    The CSS Working Group has agreed to move forward with CSS-native mixins. But some recent mixin-like CSS tricks have an advantage that the official proposal doesn’t account for: they make it easy to remove a mixin after it’s already been mixed in.

    see all Article posts
  3. Article post type

    Generating Frontend API Clients from OpenAPI

    API changes can be a headache in the frontend, but some initial setup can help you develop and adapt to API changes as they come. In this article, we look at one method of using OpenAPI to generate a typesafe and up-to-date frontend API client.

    see all Article posts