Skip to main content

CSS Responsive Design

Feature Queries

Written by Published

Apply progressive enhancements only when the browser understands a required CSS declaration or selector. It covers declaration queries, selector queries, combined conditions, progressive enhancement, and the limits of syntax-based support detection.

The @supports rule asks whether a browser understands a CSS declaration or selector. It allows an enhanced rule set to sit above a working baseline without browser sniffing.

Feature queries are most valuable when an unsupported enhancement would otherwise invalidate a layout or interaction. They do not prove that an implementation has no bugs, and they cannot replace testing. Their job is narrower: select a branch of CSS according to syntax the browser says it can parse. This topic also connects with Container Queries and Nesting & Scope.

Test a feature, not a browser

Example

css

.layout { display: block; }

@supports (display: grid) {
  .layout {
    display: grid;
    grid-template-columns: 16rem 1fr;
  }
}

@supports selector(:has(*)) {
  .field:has(:invalid) { border-color: #b91c1c; }
}

A declaration query checks whether the browser parses a property-value pair. It does not prove every edge case is bug-free.

Combine conditions

Example

css

@supports (text-wrap: balance) and (font-size: 1cqi) {
  .card-title {
    text-wrap: balance;
    font-size: clamp(1.25rem, 4cqi, 2rem);
  }
}

Feature Query Syntax

ConditionTestsExample
DeclarationWhether a property-value pair parses.@supports (display: grid)
selector()Whether a selector parses.@supports selector(:has(*))
notThe inverse of a support condition.@supports not (display: grid)
and / orA combination of support conditions.@supports (a: b) and (c: d)

Complete Example

Run the complete document below in the Try It editor. Resize the preview or interact with the controls where the example calls for it.

Complete runnable example

html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Feature Queries example</title>
  <style>
    * { box-sizing: border-box; }
    body {
      margin: 0;
      padding: 2rem;
      font-family: system-ui, sans-serif;
      line-height: 1.5;
    }
    main { max-width: 70rem; margin-inline: auto; }
    article, section, aside, form, .card, .panel {
      padding: 1rem;
      border: 1px solid #cbd5e1;
      border-radius: 0.6rem;
    }

.layout { display: block; }

@supports (display: grid) {
  .layout {
    display: grid;
    grid-template-columns: 16rem 1fr;
  }
}

@supports selector(:has(*)) {
  .field:has(:invalid) { border-color: #b91c1c; }
}

@supports (text-wrap: balance) and (font-size: 1cqi) {
  .card-title {
    text-wrap: balance;
    font-size: clamp(1.25rem, 4cqi, 2rem);
  }
}
  </style>
</head>
<body>
  <main class="layout"><label class="field">Required email <input type="email" required value="not-an-email"></label><article><h1>Progressive enhancement</h1><p>Grid and :has() styles are added only when supported.</p></article></main>
</body>
</html>

Browser Support

Feature
Chrome
Edge
Firefox
Safari
@supports2812229

Versions show the first stable desktop release with unprefixed support. Data source: MDN Browser Compatibility Data 8.0.8. A partial-support note is included where it changes how the example behaves.

Notes

  • Write a sound baseline first. A feature query should enhance that baseline, not hide essential content from older browsers.
  • Test the example with real content, keyboard input, browser zoom, and the narrowest layout your project supports.
  • Use a fallback when the support table shows that one of your required browsers predates the feature.

Conclusion

A sound baseline plus a targeted @supports enhancement is safer than browser detection.

Place essential content and a usable layout outside the query, then add the smallest enhancement inside it. If support is already universal across the project’s browser range, remove the obsolete query rather than keeping permanent scaffolding around ordinary CSS.