CSS cascade layers sound great for projects where CSS may be coming from multiple sources, and you want a nice way to manage the cascade. Unfortunately, there will still be users on older devices that don't have an up-to-date enough browser for cascade layers. Browsers that don't support cascade layers will ignore any CSS inside a layer, so these users might see a pretty broken site if you used layers extensively.
Luckily, there is a PostCSS polyfill that rewrites your CSS to add selector complexity to match the behaviour of the layers, but what if we didn't want to send users of modern browsers the polyfilled CSS?
@supports at-rule(@layer)
in CSS or
CSS.supports('at-rule(@layer)')
in JavaScript is not a
thing
yet, so we have no nice way to feature detect support for
CSS cascade layers.
This page uses edge functions to detect support for CSS cascade layers via HTTP rather than (just) CSS. You will initially be served the polyfilled CSS, but if your browser supports CSS cascade layers, you will be served the unpolyfilled CSS on subsequent requests (e.g. if you reload the page).
How it works
-
In the build process, we generate
dist/styles.css
and a polyfilled version,dist/styles-polyfilled.css
. The source of our HTML file references the polyfilled version. -
An edge function intercepts all requests to this page and checks for
the presence of a cookie called
css-cascade-layer-support
. You can see the function's code here. -
If the cookie is not present:
-
A visually hidden HTML element
<span aria-hidden="true" data-css-cascade-layers-detector></span>
is added to the page -
We lazyload a CSS file called
dist/detect.css
that contains some unpolyfilled CSS inside a layer. Browsers that don't support CSS layers will ignore this. The CSS contains a background image for[data-css-cascade-layers-detector]
that makes a HTTP request to an another edge function that returns a transparent image but also sets thecss-cascade-layer-support
cookie.
-
A visually hidden HTML element
-
If the cookie is present, we replace the
link
element that loadsdist/styles-polyfilled.css
with one that loadsdist/styles.css
, and the user gets a more simple CSS file
Checking it's working
. Try inspecting the text below to see how the cascade is working.
This text should use the Georgia font, overriding the system font
stack from the pico
layer, the Comic Sans font from the
.phils-wacky-styles--intro__text-lol
class in the
custom
layer, and instead applying the Georgia font stack
from the .font-georgia
class in the
utilities
layer.