subgrid
, and container queries: What’s new in CSSAs CSS inches closer to its 30th birthday, it continues to evolve and improve more rapidly than ever. Let’s take a cursory look at some of its newest features being shipped in the near future: cascade layers, subgrids, and container queries.
First, here’s a quick background on what exactly we mean by “cascade.”
Styles can come from a few different sources, such as the browser’s defaults or the stylesheets we author as web developers. Some of these sources take precedence over others. Traditionally, we think of the cascade as follows:
Styles in the website author’s stylesheets take precedence over the browser defaults. (This is not to be confused with selector specificity, which is resolved within each layer of the cascade.)
What the new cascade layers feature allows us to do as CSS authors is add and control additional layers of the cascade. So, rather than all of a website’s styles being lumped into a single cascade layer, authors can now create multiple cascade layers and control their order of precedence:
Before we dive into the syntax of defining cascade layers, let’s look at some use cases and problems you might solve with additional control over the cascade.
Cascade layers allow us to circumvent some of the thorniest parts of working in CSS code. In some cases, we will avoid the use of !important
because basic, over-ridable styles can simply be placed in a lower-precedence cascade layer.
For example, you might consider placing typical “reset” styles in their own cascade layer, and styles from a third-party CSS library in another. You could also put utility classes — such as those used by “atomic CSS” approaches like Tailwind CSS — into their own cascade layer to take precedence over common styles without the need for !important
.
Another use case could be dividing up an existing design system into different layers to allow for easy theming and customization. It will be interesting to see how modern JavaScript frameworks, which typically ship with workarounds like CSS modules or style encapsulation via emulated shadow DOM, adopt cascade layers to improve their developer and user experiences — although these features might be affected more directly by the @scope
proposal, which is different but related.
We define cascade layers and the styles that belong in them with the @layer
statement. Although not required, you can declare multiple layers upfront (without any styles) to determine their order of precedence, like so:
@layer reset, base, utilities;
This will create three layers called reset
, base
, and utilities
. Styles defined in utilities
will take precedence over base
styles, which will take precedence over styles in reset
.
To add styles to a layer, we define them in a block, like this:
@layer utilities { p { color: blue; } } @layer base { p { color: red; } }
Note that because we declared the layers previously and also defined their order (the initial line: @layer reset, base, utilities;
), any paragraphs on our page will be blue, even though the styles for the base
layer are defined later. Had we omitted that line, the base
layer would take precedence because it does appear later in our stylesheet, and the paragraphs would therefore be red.
It’s also possible to create anonymous layers:
@layer { p { color: green; } }
Or load external stylesheets into a particular layer:
@import url('utilities.css') layer(utilities);
We can also nest layers within other layers:
@layer outer { @layer innerOne { /* ... */ } } /* Dot syntax works, too. */ @layer outer.innerTwo { /* ... */ }
There are several options and plenty of flexibility!
Pretty soon! At the time of writing, cascade layers have already shipped to most evergreen browsers, with broader support on the way. See resources like caniuse.com for updated browser support information.
!important
noteWith the addition of multiple cascade layers, a deeper understanding of how !important
works is much more, well, important. For a clear and well-written explanation (including visuals) on the nuances of how !important
fits into the cascade and its effect on cascade layers, be sure to check out this article.
subgrid
This new feature is much simpler — at least conceptually — than cascade layers, but is certainly still exciting and much anticipated by CSS authors. Currently, grid row and column configurations only extend to the immediate children of a grid container.
Those children can also be grid containers themselves, but to achieve a consistent alignment with the parent grid, they need to carefully configure their columns or rows to match precisely those of the parent. Sometimes that’s difficult or impossible, depending on the grid settings.
With the addition of the subgrid
value for grid-template-rows
and grid-template-columns
, grid children can now inherit the grid row and column settings from the parent and properly position their children seamlessly and effortlessly, without the need to define or keep in sync with their own row and column settings. Nice!
For a more detailed explanation of subgrid
, see “Subgrid” on the MDN docs.
subgrid
?At the time of writing, only Firefox implements the new subgrid
value, but the other evergreen browsers won’t be far behind.
When browsers shipped support for media queries, the web took a giant step forward in the realm of responsive design. Media queries solved a myriad of problems, but they also exposed a new problem with complicated responsive layouts: context-aware responsiveness.
For example, you might have a component that exists within the main part of your web page and needs to change its layout based on the width of that main section. However, the width of the main section is itself dependent on the width of the browser viewport and is controlled by its own responsive layout settings.
With today’s media queries, the only way to change the layout of your inner component is to do so based on changes to the browser viewport’s width, which means you need to keep its media queries carefully in sync with those of the main section so that your component always looks correct at every viewport size. And, if you ever change your main layout, you’ll need to update your component, too.
Container queries solve this problem by allowing CSS authors to respond to the dimensions of arbitrary elements, not solely those of the viewport. This will decouple components styles from their parent containers, making responsive components vastly easier to maintain — and reduce visual layout bugs!
Unfortunately, the specification is still under active development, and no browsers have yet implemented container queries, as the final syntax is still being refined. However, it’s one of the most widely requested features, so we should see regular progress and big updates on container queries in the near future.
CSS is rapidly evolving to provide better primitives for us web developers and our users. Keep an eye on these top features for your next project!
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]