Workflow Beginner

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.

Modern
3 lines
1@supports (display: grid) {
2  .layout { display: grid; }
3}
Old JS required
1// JS: detect support, add class, then write CSS for that class
2if (CSS.supports('display', 'grid')) {
3  document.body.classList.add('has-grid');
4}
5/* CSS: */
6.has-grid .layout { display: grid; }
Widely available Since 2020 96% global usage

This feature is well established and works across many devices and browser versions. It has been available across browsers since 2020.

28+
22+
9+
12+
@supports switches layout — no JS required
Item 1
Item 2
Item 3
Item 4
@supports (display: grid) — layout switches automatically

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.

Old Approach
JS + class toggling
Modernizr or CSS.supports() then DOM mutation
Modern Approach
@supports
Conditional CSS blocks, no JavaScript
Variants
not / and / or
Combine conditions with logical operators

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.

New CSS drops.

Join 400+ readers who've survived clearfix hacks.

ESC