Building a stylesheet using cascade layers
Note:
Credit for a lot of information and ideas on this post goes to Miriam Zuzanne's A Complete Guide to CSS Cascade Layers publlished in CSS Tricks.
CSS layers present an interesting design paradigm. They allow developers to group styles based on the criteria we define.
For the example, we'll define four layers.
@layer
base
layout
utilities
theme;
The order we declare our layers is important, it will dictate how they cascade.
In our example, the rules from the theme
layer will have precedence over the rules in the layout
layer.
Using the layers we defined earlier, the cascade precedence order (from more to least important) is:
- Styles outside a layers
- base
- layout
- utilities
- theme
The !important property will change the order of properties in @layers as it does in regular stylesheets using !important
the order of precedence will be reversed before we apply our regular layer ordering
!important
theme!important
utilities!important
layout!important
base- base
- layout
- utilities
- theme
revert-layer
#
The rever-layer
keyword allows us to revert the property to the value held in the previous @layer
.
In the example below, the no-theme
class will revert the color to the previous layer, setting it green.
@layer default {
a { color: green; }
}
@layer theme {
a { color: purple; }
.no-theme {
color: revert-layer;
}
}
Adding rules to layers #
Since we declared the project layers at the top of the document and set their precedence order, we then add rules to individual layers by calling the @layer
at-rule with the name of the layer we want to place the rules in and then add as many rules as we need to.
@layer utilities {
.padding-lg {
padding: .8rem;
}
}
We can add multiple rules to each layer and we can repeat the process multiple times. Each time it will append the new rules to the layer.
Adding entire stylesheets to a layer #
We can also import stylesheets directly to a @layer using the @import at rule with a layer
attribute indicating what @layer
the browser should attach the stylesheet to.
This is particularly useful when using third-party scripts or when working with a modular architecture.
In this example, we add a local copy of normalize.css to the reset
@layer.
@import url('normalize.css') layer(reset);
Nesting layers #
we can also nest layers:
@layer defaults {
/* Ordering the sublayers */
@layer reset, typography;
@layer typography {
/* Styles go here */
}
@layer reset {
/* Styles go here */
}
}
We can reference these nested layers using a dot notation like defaults.reset
and defaults.typography
.
The rules of layer-ordering apply at each level of nesting. Any styles that are not further nested are considered “un-layered” in that context, and have priority over further nested styles:
@layer defaults {
:any-link { color: green; }
/* layered defaults (lower priority) */
@layer reset {
a[href] { color: red; }
}
}
Mixing with existing content #
My biggest issue is what to do if we're implementing layers with existing code.
All styles outside of layers are put in an implicit layer at the end of the document, making these styles the ones with the highest priority and will override all content in layers.
h1 {
color: green;
}
@layer layer-1 { h1 { color: red; } }
@layer layer-2 { h1 { color: orange; } }
@layer layer-3 { h1 { color: yellow; } }
We can get around this limitation by adding layers before the layers we create for the framework. The example below uses a lower layer to override !important
styles from the framework, and a higher layer to override normal styles.
@layer
bootstrap.important,
bootstrap.bootstrap,
bootstrap.local;
@import url('bootstrap.css') layer(bootstrap.bootstrap);
@layer bootstrap.local {
/* most of our normal bootstrap overrides can live here */
}
@layer bootstrap.important {
/*
add !important styles in a lower layer
to override any !important bootstrap
styles
*/
}
Why would we want @layers #
Layers have some interesting use cases. We've discussed some already so I'll cover one that I think it's the most important one: building a CSS architecture.
Building a CSS architecture #
I think I finally came to understand the way that @layer
s work and, in the process, I built my own structure based on my project's needs. Something like this from generic to specific:
- default styles (these could be nested or not)
- reset or normalize scripts
- base styles for components if no design system is applied
- typography
- External styles from libraries or design system
- themes
- overrides
In the end, how you structure your layers is up to you and what makes the most sense for your project.
Links and resources #
- @layer — MDN
- Cascade Layers — Chrome Developers
- A Complete Guide to CSS Cascade Layers
- Hello, CSS Cascade Layers