There is a new thing coming in CSS: @layer
.
This comes from Miriam Suzanne, who is really on a tear with influencing important new CSS stuff. I’ve been hearing about all this, but then all a sudden it just dropped in experimental browsers.
Leave it to Bramus to really dig into all this with a fantastic post on it all:
With Cascade Layers coming, we developers will have more tools available to control the Cascade. The true power of Cascade Layers comes from its unique position in the Cascade: before Selector Specificity and Order Of Appearance. Because of that we don’t need to worry about the Selector Specificity of the CSS that is used in other Layers, nor about the order in which we load CSS into these Layers — something that will come in very handy for larger teams or when loading in third-party CSS.
Bramus Van Damme, “The Future of CSS: Cascade Layers (CSS@layer
)“
Emphasis mine.
That’s the rub here: this is a new thing that affects which selectors win. It’s going to require some re-wiring of our CSS brains, because layers is this entirely new (and powerful) part of determining what styles actually get applied.
I say powerful because a “higher” layer can literally beat a traditionally stronger selector even with a weaker selector in the layer.
/* First layer */
@layer base-layer {
body#foo {
background: tan;
}
}
/* Higher layer, so this wins, despite selector strength */
@layer theme-layer {
body.foo {
background: #eee;
}
}
/* Careful! Unlayered styles are more powerful than layers, even if the selector is weaker */
body {
background: red;
}
Because that CSS at the bottom isn’t in a layer at all, it wins, even with the weaker selector
And you aren’t limited to one layer. You get to define them and use them however you want.
@layer reset; /* Create 1st layer named “reset” */
@layer base; /* Create 2nd layer named “base” */
@layer theme; /* Create 3rd layer named “theme” */
@layer utilities; /* Create 4th layer named “utilities” */
/* Or, @layer reset, base, theme, utilities; */
@layer reset { /* Append to layer named “reset” */
/* ... */
}
@layer theme { /* Append to layer named “theme” */
/* ... */
}
@layer base { /* Append to layer named “base” */
/* ... */
}
@layer theme { /* Append to layer named “theme” */
/* ... */
}
Mind-blowing, really.
How are we going to use this?
I wonder if a common pattern might turn into…
- Layer everything, so priority levels are really clear. Maybe allow unlayered CSS for super powerful overrides only, but ideally even do that as a high-level layer.
- Resets as the lowest layer.
- Third-party stuff as the middle layer(s).
- Anything team-authored as the highest layer.
You won’t have to worry about leaving space in between (like you might with z-index
) because you can adjust it without needing to attach numbers at any time.
Time shall tell.
Debugging
I hope DevTools expresses layers really clearly because there is going to be some serious head-scratching for a while when we see weaker-looking selectors winning because of layer placement.
Browser Support
Looks like caniuse is on the ball here!
This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.
Desktop
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
99 | 97 | No | 99 | 15.4 |
Mobile / Tablet
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
115 | 115 | 115 | 15.4 |
Updates
This stuff is super new (at the time of writing), so volatility is to be expected, I suppose. Looks like on October 6th, 2021 it was decided that unlayered styles are actually the strongest styles, not the weakest. I’ve attempted to update the article to show that.
I don’t want to be rude, but i literally can’t see the usefulness of this.
Can someone give me a plausible example?
Thanks a lot!
It will be useful to override existing styles. Say I’m working on a site for a large organization overreaching central CSS. They might have a style like:
To override that, I’d need to match the specificity and have my CSS come later, or beat the specificity. If the markup is out of my control, and there are no other classes, then I’m out of luck.
However, I could just add it to a layer. Layered styles beat unlayered so my override could just be:
Of course for a single case like this, inline might be the way to go, but it gets more useful as more declarations are needed.
Another example is if you’re importing third-party CSS. You could put that all in a
@third-party
layer, then user an@third-party-override
layer to make tweaks.Yeah, that doesn’t seem like a good thing. Feels like it’s introduce the same sort of problems as adding !important to everything.
Also, in that example, could you not just repeat a class to increase the specificity?
I see this potentially being a net-negative, where this adds an extra level of complexity in the specificity wars. I foresee third-party components with fully “layered” styles because they don’t want them overridden, and then devs being tasked with overriding them.
That’s what I was thinking
If you create a layer to override their layer before you include their layer, you win. Unless the third-party components have some way of forcing their layer to be defined first (injected by JavaScript, perhaps?), they don’t have a mechanism to force the issue.
Now, I can see something like Next/Nuxt/etc. being able to force this, but I don’t see those kinds of frameworks doing much styling.
You don’t need to declare your layer first, so you don’t need to worry about that.
If you want to override a layer, just have your layer after it, just like the usual cascading override that gave its name to CSS.
And since unlayered rules now take priority in the last draft (october 2021), it seems to be going to be even easier.
Looks like
@layer
will be the new!important
:PI see people in the comments here making comparisons to
!important
… I think it’s a fair comparison because that’s one of the closest tools we have to layers at the moment.However, I think it’s also too narrow of a comparison. If your CSS is pretty static over time and you control all of it, then layers might not bring a huge benefit (though, that is yet to be seen since it offers a new structural aspect to CSS).
But, if you are using 3rd party CSS or an internal shared bit of CSS, layers allow those styles to be simplified (eg look at Bootstrap’s styles which have
!important
everywhere) because they can rely on the developer putting their own CSS in a lower layer, or eventually they could ship their CSS in a predefined layer and let developers position it within their CSS hierarchy as needed.I think layers will remove the need for
!important
within our own CSS and within 3rd party CSS. It adds another dimension to the cascade that works at the macro scale, which lets us use selector specificity and selector order to tune things at the micro scale.I think this is a great feature!
Exactly. The problem with
!important
is it was declaration-specific, and might pop up in any ol’ context of the cascade, obliterating other specificity factors in the process.@layer
is a farcry from that. It lets you manage specificity in god mode at a macro scale. We’ll be able to take a project’s entire architecture into consideration, setting outer boundaries for specificity, but then letting “members” of individual layers duke it out from there.Definitely looking forward to this.
This CSS layers thing is quite interesting stuff, no question about it.
But… What is the problem they are trying to solve in the first place?
I did not get about sort order. Will it be determined based on declaration sort order still?
It sounds like they are something similar to namespaces. We will be able override thing in scope of particularly namespases.
Looks like the latest Safari Technology Preview (Release 132) includes CSS Cascade Layers as Experimental Feature (Develop → Experimental Feature → CSS Cascade Layers)
Looks like
@import
to me, but inline.From an accessibility standpoint, I wonder how @layer will impact people who use custom user style sheets.
we’re far from a11y experts, but are thinking a lot about browser extensions and the like, and think this should be a net-positive in the long run, but might take some re-writing of scripts in the short term. in the future, it should be easy to write user styles in a higher layer, such that your styles are always applied.
“It lets you manage specificity in god mode at a macro scale”
Perfectly said.
Some Saas software allows you to add your own custom CSS to “theme” the app atop a base css theme – which can’t be removed. A lot of the time their choice of CSS selectors leaves a lot to be desired. @layers makes perfect sense in this instance, you can just wipe that clean and start fresh. Unless I’ve got my layers crossed ;)
Are layers usable with JavaScript
I see a positive side of this feature regarding ability to “sort” base CSS, resets etc.
But, if you can create a layer anywhere in your code, doesn’t it mean that it’s gonna be a feature duplicating functionality of
z-index
?I think this is it.
I started writing CSS2 stylesheets in 2003 but had only passing familiarity with JS until 2013-15 (progressing modestly until 2018).
Because I had 10-12 years more experience in CSS, even when I got my head around scope in JS, I didn’t get what the big deal was about not casually putting things (some things, many things, everything) in global scope.
In hindsight, it occurs to me this was because in a CSS stylesheet – the paradigm I was much more familiar with – everything (unless you count media queries as quasi-scoping) is in global scope.
So I globally scoped my JS in the same way I globally scoped my CSS – and learned better only later.
But with the introduction of CSS Cascade Layers, there is now a CSS global scope: unlayered styles.
So, in the same way globally scoped variables appear only rarely in JS Best Practice, in some potential future CSS Best Practice
@layer
will be deployed everywhere to ensure globally scoped styles appear rarely, too.This approach would mean that, absent very good reason, no styles should be unlayered and, instead, CSS Cascade Layers would become a mainstay of most stylesheets, alongside e.g. CSS Custom Properties and Touchscreen Media Queries.
The question “But when should I use
@layer
?” (somewhat) recalls the question “But when should I useconst
?” after the introduction oflet
andconst
in ES2015.Only when a more progressed understanding evolved, did many ES2015 devs reframe that question as: “When shouldn’t I use
const
?”:So maybe that’s it. Maybe instead of asking when we should use Cascade Layers we will benefit greatly by adopting
@layer
across the board and recognising that the more important question any of us could ask is: