What? How? Why? @layer
24 October 2022An introduction to the @layer
rule in CSS. Understand why you might want to use it, as quickly as possible.
What is it?
The cascade in CSS is the algorithm that determines what styles are applied when there are multiple style sources. On a day-to-day basis, you and I are most concerned with how that cascade resolves different rulesets trying to apply different styles to the same element. There are a lot of rules to this, but the ones we're most concerned with are specificity and order of appearance. The most specific selector wins, and if the selectors have the same level of specificity; the ruleset that appears last wins.
Sometimes the way the cascade styles your web page is not the way you wanted, perhaps your desires are colliding with the desires of another module you've written and included on the page, or with an external framework. You can fix this on a case by case basis by writing more specific selectors or using the brute-force method of !important
.
The @layer
rule attempts to give more control over the cascade by enabling us to define our own cascade layers as well as their order of importance, so your styles come out exactly the way you intended.
How do I use it?
@layer {
p {
color: pink;
}
}
That's it. That's an anonymous (unnamed) cascade layer.
You can name them, too.
@layer cake {
p {
color: pink;
}
}
The power of @layer
comes from being able to define their order of importance.
@layer base, new;
@import url(base.css) layer(base);
@layer new {
p {
color: orange;
}
}
Say our company has a set of base styles shared across our apps, we've imported these, and it tells all our paragraphs to have a text color
of black. But what if we're on our fifth redesign of the year and want to try out some new styles gradually? By defining the new
layer, we can write some neatly defined overrides. Importance is defined in ascending order; in the snippet below, "new" is more important than "base".
Be aware that styles you define in layers will always be less important than your existing unlayered styles, unless you wrap all your existing styles in a layer. Also, if you define no order of importance to your layers then they will be subject to the usual rules of the cascade: the last layer to appear is the “winner”.
Why would I use it?
It's a nice way to organise your styles. For each component you build in a design library, for instance, you could structure your CSS Module in multiple layers. Not the main reason for @layer
but it looks cute and clean.
/** footer.css **/
@layer variables {}
@layer spacing {}
@layer typography {}
@layer colour {}
@layer animation {}
If you're a user of CSS resets, you may want to ensure that this has the lowest priority in your cascade to ensure your own styles take precedence. Resets provide a baseline and should be easily overwritten.
/** global.css **/
@layer resets, then, everything, else;
@import url(reset.css) layer(reset);
@import url(then.css) layer(then);
@import url(everything.css) layer(everything);
@import url(else.css) layer(else);
If you're using an external library that takes it upon itself to annoy you by writing ridiculously specific rulesets that are hard to override, you can use nested layers to put that framework in its place.
/** external.css **/
@layer external.tootstrap, external.sailwind, external.overrides;
@import url(tootstrap.css) layer(external.tootstrap);
@import url(sailwind.css) layer(external.sailwind);
@layer external.overrides {
p {
color: yellow;
}
}
Should I use it?
At the time of writing, @layer is a “candidate recommendation” and is not something to start using in your every day work. Unlike other new CSS features, this one's going to take a while to… cascade… into robust browser support. So, no, I wouldn't use it right now.
When @layer
does receive widespread support, I would use it if:
- I experienced a lot of conflicting styles with rulesets I had no control over
- I wanted to have a pretty structure of layers for ease of readability
I wouldn't use it if:
- I had very few conflicting styles easily resolved by increased specificity of my selectors or promising I'd only use
!important
just this once 👀 - I thought it was going to take care of my cascade issues magically,
@layer
use can still result in conflicts, and you can still throw!important
on everything if you're an agent of chaos