# CSS @supports and Feature Queries: Progressive Enhancement Guide

Source: https://devdocs10.com/articles/css/css-supports  
By Murat Bo · Published 2026-09-14 · DevDocs10 (https://devdocs10.com)

CSS `@supports` lets you apply styles only when a browser understands a particular CSS feature. It is one of the most practical tools for progressive enhancement because it helps you write modern styles without breaking older browsers.

> **Quick answer:** Use `@supports` when you want a feature-based fallback, not a screen-size fallback. It checks whether the browser recognizes a property, value, or selector pattern before applying the enclosed rules.

> **Difficulty:** Beginner to Intermediate
>
> **You'll understand this better if you know:** basic CSS rule syntax, how selectors and declarations work, and the difference between browser support and layout breakpoints.

## 1. What Is CSS @supports?

`@supports` is a CSS at-rule that lets you ask the browser, “Do you support this feature?” If the answer is yes, the browser applies the styles inside the block. If not, it skips them.

- It performs feature detection in CSS.
- It works with properties, values, and some selector checks.
- It helps you ship modern styles safely while keeping fallbacks available.
- It is commonly used with newer layout features like Grid, `backdrop-filter`, or custom selectors.

This is different from media queries, which check the device or viewport, not whether a CSS feature exists.

## 2. Why @supports Matters

Browsers do not all gain new CSS features at the same time, and some features may be partially supported. Without feature queries, a modern declaration might be ignored silently or may create an inconsistent experience. `@supports` gives you a clean way to layer advanced styling on top of safe defaults.

That matters when:

- you want a fallback layout for older browsers,
- you are using a new CSS property that may not be available everywhere,
- you want to avoid duplicate classes or user-agent checks,
- you need the stylesheet itself to decide which styles are safe to use.

## 3. Basic Syntax

The basic form is simple: write a condition inside `@supports`, then place the supported styles in the block.

### Minimal example

This example checks for `display: grid`. If the browser supports Grid, it uses the Grid layout rules.

```css
@supports (display: grid) {
  .layout {
    display: grid;
    grid-template-columns: 1fr 2fr;
    gap: 1rem;
  }
}
```

The condition tests a feature, and the browser only applies the styles inside the block when that test succeeds.

### Using a fallback first

The most reliable pattern is to write a safe default first, then enhance it with `@supports`.

```css
.layout {
  display: block;
}

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

Browsers that do not support Grid keep the block layout, while modern browsers upgrade to Grid.

## 4. Step-by-Step Examples

### Example 1: Enhancing layout with CSS Grid

Start with a flexible fallback, then switch to Grid when available. This is a common real-world use of feature queries.

```css
.cards {
  display: block;
}

.card {
  margin-bottom: 1rem;
}

@supports (display: grid) {
  .cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1rem;
  }

  .card {
    margin-bottom: 0;
  }
}
```

This approach prevents older browsers from getting a broken grid-only layout.

### Example 2: Supporting modern color functions

Some browsers support newer color syntax before others. You can use `@supports` to introduce the modern version safely.

```css
.button {
  background-color: #1d4ed8;
  color: #fff;
}

@supports (color: oklch(0.6 0.15 250)) {
  .button {
    background-color: oklch(0.55 0.18 250);
  }
}
```

The fallback color remains available, and newer browsers get the improved color expression.

### Example 3: Checking support for a property value

Feature queries can test more than a property name. They can test whether a specific value is accepted.

```css
.panel {
  padding: 1rem;
  border-radius: 0.5rem;
}

@supports (backdrop-filter: blur(10px)) {
  .panel {
    backdrop-filter: blur(10px);
    background-color: rgba(255, 255, 255, 0.65);
  }
}
```

Using a value test helps when a property exists but only certain values are actually useful for your design.

### Example 4: Combining conditions

You can combine checks with `and`, `or`, and `not`. That makes it possible to target more specific support scenarios.

```css
@supports (display: grid) and (gap: 1rem) {
  .layout {
    display: grid;
    gap: 1rem;
  }
}

@supports not (display: grid) {
  .layout {
    display: block;
  }
}
```

Logical operators let you build precise conditions for advanced compatibility strategies.

## 5. Practical Use Cases

Feature queries are especially useful in projects that mix stable baseline styles with newer enhancements. Common situations include:

- Switching from float-based or block-based layouts to Grid or Flexbox when supported.
- Applying visual polish such as `backdrop-filter`, `subgrid`, or advanced color syntax only in capable browsers.
- Guarding experimental or newer properties so fallback styling still looks acceptable.
- Building design systems that need one stylesheet to serve multiple browser generations.
- Creating print or embedded views that must stay readable even when advanced features are missing.

## 6. Common Mistakes

### Mistake 1: Using @supports like a media query

`@supports` checks feature support, not viewport width or device type. Developers sometimes expect it to react to screen size, but it will not.

**Problem:** This code tries to show a two-column layout only on wide screens, but it incorrectly uses a feature query instead of a media query.

```css
@supports (min-width: 900px) {
  .layout {
    display: grid;
  }
}
```

**Fix:** Use a media query for viewport conditions, and reserve `@supports` for feature checks.

```css
@media (min-width: 900px) {
  .layout {
    display: grid;
  }
}
```

The corrected version works because it uses the right CSS tool for the job.

### Mistake 2: Forgetting the fallback styles

If you place all styling inside `@supports`, unsupported browsers may end up with a poor or incomplete experience.

**Problem:** The base layout is missing, so browsers that do not pass the feature query see almost no usable structure.

```css
@supports (display: grid) {
  .cards {
    display: grid;
    gap: 1rem;
  }
}
```

**Fix:** Write a simple baseline first, then enhance it inside the feature query.

```css
.cards {
  display: block;
}

@supports (display: grid) {
  .cards {
    display: grid;
    gap: 1rem;
  }
}
```

The fallback ensures the content remains usable everywhere.

### Mistake 3: Testing only a property name when the value matters

Sometimes the browser supports a property in general, but not the exact value you want to use. Testing only the property can lead to misleading results.

**Problem:** This code assumes any support for `color` means the browser supports the modern color function being used.

```css
@supports (color: red) {
  .badge {
    color: oklch(0.7 0.2 200);
  }
}
```

**Fix:** Test the exact feature you want to use, including the value syntax when needed.

```css
@supports (color: oklch(0.7 0.2 200)) {
  .badge {
    color: oklch(0.7 0.2 200);
  }
}
```

The corrected version checks the exact capability that the style depends on.

## 7. Best Practices

### Practice 1: Start with a working baseline

Always make the default experience usable without `@supports`. Then layer enhancements on top. This keeps the page readable even in older browsers.

```css
.toolbar {
  display: block;
}

@supports (display: flex) {
  .toolbar {
    display: flex;
    justify-content: space-between;
  }
}
```

This pattern reduces the risk of a completely broken layout when the feature is unavailable.

### Practice 2: Keep conditions specific

Use the narrowest useful condition. A specific query is easier to maintain than a broad one that accidentally matches too much.

```css
@supports (display: grid) {
  .gallery {
    display: grid;
  }
}
```

Specific checks make it clear exactly which feature unlocks the enhancement.

### Practice 3: Use feature queries for CSS, not for business logic

`@supports` should decide styling only. It is not a substitute for product decisions, access control, or application behavior.

```css
@supports (backdrop-filter: blur(10px)) {
  .modal {
    backdrop-filter: blur(10px);
  }
}
```

That keeps feature detection where it belongs: inside the stylesheet.

## 8. Limitations and Edge Cases

- `@supports` only tells you whether the browser claims to support the feature syntax; it does not guarantee a feature is visually perfect in every situation.
- Some properties may be partially supported, so a positive result does not always mean identical rendering across browsers.
- Browser support for a selector test can be narrower than support for a plain property check.
- Feature queries cannot detect bugs in a browser implementation; they only check support status, not correctness of behavior.
- If a browser ignores the whole `@supports` rule because it does not understand it, your fallback styles must already exist outside the block.
- Nested `@supports` rules can become hard to read if you stack too many conditions without clear structure.

> **Note:** If you need broad compatibility, test real browsers and devices. Feature queries reduce risk, but they do not replace compatibility testing.

## 9. Practical Mini Project

Here is a small card component that starts with a simple stacked layout and upgrades to a more modern layout when Grid is available.

```css
.product-list {
  display: block;
}

.product-card {
  padding: 1rem;
  margin-bottom: 1rem;
  border: 1px solid #d1d5db;
  border-radius: 0.5rem;
}

@supports (display: grid) {
  .product-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem;
  }

  .product-card {
    margin-bottom: 0;
  }
}
```

This example is complete enough to copy into a real stylesheet. Older browsers get a plain stacked list, while newer browsers get a responsive Grid layout.

## 10. Key Points

- `@supports` applies styles only when a CSS feature is supported.
- It is for feature detection, not screen-size detection.
- Write a solid fallback first, then enhance the experience inside the query.
- Test the exact property or value you depend on.
- Use it to improve compatibility, not to replace browser testing.

## 11. Practice Exercise

- Create a card layout with a simple block fallback.
- Add an `@supports` rule that upgrades the layout to Grid.
- Include one optional enhancement such as `backdrop-filter` or a modern color value.

**Expected output:** In browsers that support the tested features, the cards should be arranged in columns with extra styling. In older browsers, the cards should still stack vertically and remain readable.

**Hint:** Put the fallback styles outside `@supports`, and only place the modern enhancement inside the feature query.

**Solution:**

```css
.demo-cards {
  display: block;
}

.demo-card {
  padding: 1rem;
  margin-bottom: 1rem;
  background: #f9fafb;
  border: 1px solid #e5e7eb;
}

@supports (display: grid) {
  .demo-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1rem;
  }

  .demo-card {
    margin-bottom: 0;
  }
}
```

This solution works because the fallback is usable on its own, and the enhanced version only replaces it when the browser can handle the new layout.

## 12. Final Summary

CSS `@supports` is a feature query mechanism that helps you write safer, more resilient styles. It lets you detect whether a browser supports a property, value, or selector pattern before applying enhanced rules.

Use it to layer modern CSS on top of a dependable fallback. That way, older browsers still get a usable experience, and newer browsers can take advantage of richer layout and visual features.

As you keep building with modern CSS, pair `@supports` with real browser testing and clear fallbacks. The combination gives you progressive enhancement that is practical, maintainable, and predictable.

## Browser Support

| Feature | Status | Chrome | Edge | Firefox | Safari | Safari iOS |
| --- | --- | --- | --- | --- | --- | --- |
| @supports | Widely available since Mar 2018 | 28+ | 12+ | 22+ | 9+ | 9+ |

Data: web-features 3.43.0 (MDN Baseline).
