feature query in CSS: test a property before you rely on it

The @supports feature query checks that a browser understands a CSS property before you rely on it, so you can write a clean fallback.
5 min read
Believemy logo

Not every browser understands the same CSS properties at the same time. A newer feature like subgrid or backdrop-filter might work perfectly in a recent browser while being silently ignored in an older one, with no error message at all: the line is simply skipped. A feature query exists for exactly this situation: it asks the browser, in plain CSS, whether it understands a given property before you depend on it.

It differs from a Media query, which asks about the display environment, its size, its orientation: a feature query asks about the rendering engine itself. It is the tool that lets you offer a modern layout to browsers that support it while keeping a correct, simpler layout for the rest, with no JavaScript involved.


Definition

A feature query is a conditional CSS rule that starts with @supports and only applies the styles inside it when the browser recognizes the property and value being tested. Unlike a media query, which reacts to the display environment, a feature query reacts to the capabilities of the CSS engine itself. It lets you write a modern style with confidence, while providing a fallback for browsers that do not support it yet.


Basic syntax

The syntax reuses a property and a value, exactly as in a normal declaration, but wrapped in parentheses after @supports. If the test passes, the block that follows is applied normally, just like any other CSS rule.

CSS
@supports (display: grid) {
  .container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
  }
}

Outside that block, you usually write a fallback style that works everywhere. A browser that does not understand grid keeps using that fallback and never enters the @supports block at all.


Combining several conditions

@supports accepts the and, or, and not operators to build more precise conditions. This becomes useful when a feature depends on two properties at once, or when you want to specifically target browsers that do not support a novelty yet.

CSS
@supports (display: grid) and (gap: 1rem) {
  .container {
    display: grid;
    gap: 1rem;
  }
}

@supports not (aspect-ratio: 1 / 1) {
  .thumbnail {
    padding-top: 100%;
  }
}

not is especially handy for writing the fallback right inside its own @supports block, instead of leaving it outside any condition where it could accidentally be overwritten later.


Concrete example: layout with a fallback

Here is a common case: a card grid that uses CSS Grid in modern browsers, with a flexible column fallback for the rest.

CSS
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.cards > * {
  flex: 1 1 280px;
}

@supports (display: grid) {
  .cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  }
}

The flex style acts as a universal baseline. The @supports block then fully replaces it in browsers that understand grid, so no visitor ever ends up with a broken page.


Testing a value, not just a property

A common trap is assuming that @supports only checks a property name. In reality you should always test a property and value pair together, because a property can exist for years while gaining new values much later.

CSS
/* Wrong: position has existed forever */
@supports (position) {
  .bar {
    position: sticky;
  }
}

/* Right: test the actual declaration you plan to use */
@supports (position: sticky) {
  .bar {
    position: sticky;
  }
}
Good to knowAlways test the exact declaration you intend to use, property and value together. Testing the property alone almost always returns true, even in a browser that has no idea what the modern value means, which makes the test useless.


Common use cases

Feature queries are mostly useful for recent or compatibility-sensitive properties: subgrid, grid itself in its early days, or costly effects like a background filter. They also document intent in the code: a developer reading the file immediately understands that a style is conditioned on a specific browser capability.

SituationGood habit
New, not-yet-widespread propertyFallback style outside @supports, enhancement inside it
Two related properties (grid and gap, for instance)Combine them with and in a single condition
Explicitly targeting an old browserUse not to isolate that case


FAQ

QuestionDoes a feature query slow down the page render?

No, the test is evaluated once by the browser when the stylesheet loads, exactly like any other CSS rule: there is no noticeable performance cost in practice.

QuestionCan @supports test JavaScript or HTML features?

No, @supports only tests CSS declarations. To detect a JavaScript API you need a script-side check, for example the CSS.supports() object, which mirrors the same logic in JavaScript.

QuestionWhat happens if a browser does not understand @supports at all?

Browsers old enough to ignore @supports also ignore the entire rule, including its content, so they naturally fall back to the style written outside the block, which makes this technique safe by construction.

Related terms

Discover our hTML and CSS glossary

Browse the terms and definitions most commonly used in HTML and CSS development.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.