Learn how to use the CSS @supports rule to apply styles only when a browser confirms it understands specific features, enabling robust progressive enhancement.
What it is
The @supports at-rule allows you to conditionally apply CSS declarations based on whether the user's browser supports a particular feature. Unlike JavaScript-based feature detection (like Modernizr), this happens entirely within your stylesheet. It acts as a gatekeeper: if the test inside the parentheses evaluates to true, the enclosed rules are applied; otherwise, they are ignored.
Think of it as asking the browser, "Do you understand this syntax?" If yes, proceed with the advanced styling. If no, fall back to simpler, widely supported styles defined outside the block.
Why it matters
- Prevents layout breakage: Ensures complex layouts (like Grid or Flexbox) don't render incorrectly in older browsers that lack support.
- Reduces JavaScript dependency: Keeps feature detection logic in CSS, improving performance and separation of concerns.
- Enables safe experimentation: Allows developers to adopt new CSS features early without breaking existing functionality for users on legacy systems.
- Cleaner code structure: Groups fallbacks and enhancements logically within the same file rather than scattering them across multiple files or scripts.
Syntax or steps
The basic syntax requires a property-value pair wrapped in parentheses. You can also test for boolean values using true or false, though testing actual properties is more common.
@supports (property: value) {
/* Styles applied only if the browser supports the property */
}
@supports not (property: value) {
/* Styles applied only if the browser does NOT support the property */
}
You can combine tests using logical operators like and and or.
Example
Here is a practical example implementing a responsive card layout using CSS Grid, with a fallback to Flexbox for browsers that do not support Grid.
.card-container {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 300px;
padding: 1rem;
border: 1px solid #ccc;
}
/* Progressive Enhancement: Use Grid if supported */
@supports (display: grid) {
.card-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 1.5rem;
}
.card {
flex: none; /* Reset flex property since we are using grid now */
}
}
Explanation:
- The base styles define a Flexbox layout. This ensures all browsers have a functional layout.
- The
@supportsblock checks if the browser understandsdisplay: grid. - If supported, the container switches to Grid, offering better control over rows and columns.
- The
.cardrule inside the block resets theflexproperty to prevent conflicts between the two layout models.
Common mistakes
- Testing invalid syntax: Ensure the property and value inside the parentheses are valid CSS. For example,
@supports (color: red)works, but@supports (color: #GGG)might fail depending on strictness. - Forgetting fallbacks: Always define default styles outside the
@supportsblock. If you rely solely on enhanced styles, unsupported browsers will show unstyled content. - Overusing
not: While@supports not (...)is useful, prefer positive tests (@supports (...)) for clarity. Negative tests can sometimes be harder to maintain. - Nesting complexity: Avoid deeply nested
@supportsblocks. Flatten your logic where possible to keep the stylesheet readable.
When to use it
Compare @supports with JavaScript feature detection libraries like Modernizr.
| Feature | CSS @supports | JavaScript Detection |
|---|---|---|
| Performance | High (no JS execution needed) | Lower (requires script parsing/execution) |
| Scope | CSS-only features | Any DOM/CSS/HTML feature |
| Complexity | Low (declarative) | Medium (imperative logic) |
| Best For | Layouts, animations, typography | API availability, HTML5 input types |
Use @supports whenever the feature being tested is purely presentational. Use JavaScript detection when you need to alter DOM structure or behavior based on capability.
Practice
Guided Exercise: Write a CSS rule that applies a backdrop-filter: blur(10px); to an element with class .glass-panel only if the browser supports it. Provide a solid background color as a fallback.
Challenge: Create a media query combined with a feature query. Apply a dark theme only if the user prefers dark mode AND the browser supports CSS variables.
Hint: Use @media (prefers-color-scheme: dark) wrapping an @supports (--custom-property: initial) block.
Quick check
Question: What happens to the styles inside an @supports block if the browser does not recognize the tested feature?
Answer: The entire block is ignored by the browser, and any fallback styles defined outside the block remain active.
Summary
The @supports rule is a powerful tool for progressive enhancement, allowing CSS to adapt dynamically to browser capabilities without JavaScript. By defining robust fallbacks and layering advanced features, you ensure consistent user experiences across diverse environments.