CSS feature detection without JavaScript
Detecting CSS feature support required JavaScript — either Modernizr, inline CSS.supports() checks, or testing computed styles. @supports lets CSS apply styles conditionally based on whether the browser supports a given property and value.
2 .layout { display: grid; }
3}
2if (CSS.supports('display', 'grid')) {
3 document.body.classList.add('has-grid');
4}
5/* CSS: */
6.has-grid .layout { display: grid; }
Browser Support for Css featurequeries
This feature is well established and works across many devices and browser versions. It has been available across browsers since 2020.
Detection and fallback in one place
@supports keeps feature detection in CSS where the styles live. No JS, no class toggling, no DOM mutation to apply a CSS branch.
Supports not, and, or
@supports not (), @supports (a) and (b), and @supports (a) or (b) cover all combinatorial cases for progressive enhancement.
Selector detection too
@supports selector(:has()) tests whether a CSS selector is supported — useful for detecting newer pseudo-classes before using them.
How it works
Progressive enhancement with JavaScript meant detecting support, adding a class to the root element, then writing separate CSS for that class. This split the feature logic across two files and required JS to run before styles applied correctly — a fragile dependency.
@supports is a CSS conditional block. Styles inside only apply when the browser supports the tested declaration. @supports not provides a fallback path. @supports selector(:has()) tests selector support. Because the detection is in CSS, no JavaScript is needed and styles are self-contained.