CSS@supports Feature Queries

@supports Feature Queries

@supports lets you write CSS that only applies if the current browser actually understands a given property/value pair. It works exactly like a media query, except instead of testing the viewport it tests CSS feature support itself — making it the standard tool for progressively enhancing a page based on real capability rather than guessing from a user agent string.

Basic Syntax

CSS
@supports (display: grid) {
  .layout {
    display: grid;
  }
}

@supports not (display: grid) {
  .layout {
    display: flex; /* fallback for browsers without grid */
  }
}

The condition inside the parentheses is a property/value pair, not just a property name — @supports (display: grid) checks specifically whether the browser supports grid as a value of display, which is important because a browser might support the display property in general while not supporting every value it can take.

Combining Conditions

Operator

Meaning

Example

and

Both conditions must be supported

@supports (display: grid) and (gap: 1rem)

or

Either condition being supported is enough

@supports (backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))

not

Negates a condition

@supports not (display: grid)

CSS
/* Require both features together */
@supports (display: grid) and (gap: 1rem) {
  .grid {
    display: grid;
    gap: 1rem;
  }
}

/* Accept either the standard or webkit-prefixed version */
@supports (backdrop-filter: blur(6px)) or
  (-webkit-backdrop-filter: blur(6px)) {
  .glass-panel {
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
}
Worked Example: Flexbox Fallback, Grid Enhancement

A common pattern is to write a Flexbox layout that works everywhere as the baseline, then override it with Grid only in browsers that support it — giving modern browsers the more powerful layout tool while older browsers still get a perfectly usable page.

CSS
/* Baseline: works in every browser, including ones without Grid */
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.cards > .card {
  flex: 1 1 240px;
}

/* Enhancement: only browsers that support Grid get this layout */
@supports (display: grid) {
  .cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  }
  .cards > .card {
    flex: unset; /* no longer relevant once we're on Grid */
  }
}

Because the Flexbox rules are declared first and the @supports block comes after, browsers that don't understand @supports at all simply ignore the block they can't parse and keep the Flexbox layout — no explicit fallback logic required.

Note
@supports is the standard, robust way to progressively enhance CSS based on actual feature support. Detecting browsers by sniffing the user agent string is unreliable (user agents can be spoofed, inconsistent, or simply wrong about what the browser supports going forward) and is strongly discouraged — always test for the feature itself.