Over-engineered feature detection of CSS cascade layer support with edge functions

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

  1. 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.
  2. 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.
  3. If the cookie is not present:
    1. A visually hidden HTML element <span aria-hidden="true" data-css-cascade-layers-detector></span> is added to the page
    2. 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 the css-cascade-layer-support cookie.
  4. If the cookie is present, we replace the link element that loads dist/styles-polyfilled.css with one that loads dist/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.