What is CSS Feature Detection?
CSS feature detection is the practice of testing whether a browser understands and can apply specific CSS properties, values, or selectors before using them in your stylesheets. This approach enables progressive enhancement--building experiences that work everywhere but take advantage of modern capabilities where supported.
The @supports at-rule, part of the CSS Conditional Rules module, provides a native way to perform these tests directly in your CSS without requiring JavaScript detection or external libraries. Modern web development requires balancing cutting-edge CSS features with browser compatibility, and @supports is the essential tool for safely adopting new capabilities.
Browsers release new features and fixes monthly, and the CSS Working Group constantly works on specifications. The challenge for developers is knowing when it's safe to use new features and how to provide alternatives when they aren't supported. A key reason feature detection with @supports works effectively is that CSS fails silently--when a browser encounters a property or value it doesn't understand, it simply skips that declaration without breaking the entire stylesheet.
1/* Test if browser supports a property */2@supports (display: flex) {3 .container {4 display: flex;5 justify-content: center;6 align-items: center;7 }8}9 10/* Test if browser supports a specific value */11@supports (aspect-ratio: 16 / 9) {12 .video-wrapper {13 aspect-ratio: 16 / 9;14 }15}Modern web development requires balancing cutting-edge CSS features with browser compatibility
Progressive Enhancement
Build experiences that work everywhere, then enhance for capable browsers without leaving anyone behind
Graceful Degradation
Maintain functionality across all browsers while offering advanced features where supported
No JavaScript Required
Perform feature detection natively in CSS without external libraries or client-side scripts
Better User Experience
Deliver modern, performant experiences to users with updated browsers while ensuring core functionality for all
Using Logical Operators
The @supports rule supports logical operators for combining multiple conditions when you need to test for multiple features simultaneously.
The and Operator
Require ALL conditions to be true by combining conditions with and. This is useful when you need multiple features working together, such as combining CSS Grid with gap support:
@supports (display: grid) and (grid-gap: 1rem) {
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
}
The or Operator
Apply styles when ANY condition is true using the or operator. This pattern is particularly useful for vendor prefix handling:
@supports (-webkit-font-smoothing: antialiased) or
(font-smooth: always) {
body {
-webkit-font-smoothing: antialiased;
font-smooth: always;
}
}
The not Operator
Apply styles when a feature is NOT supported. Negative detection is useful when you need to provide significant fallback styling that differs substantially from the enhanced version:
@supports not (display: grid) {
.gallery {
display: flex;
flex-wrap: wrap;
}
}
Positive detection (@supports (feature)) is generally preferred because it's more maintainable as browser support improves and the cascade naturally handles fallbacks when modern styles come after baseline declarations.
Progressive Enhancement Patterns
Pattern 1: Aspect Ratio with Fallback
The aspect-ratio property is a medium-impact feature that benefits from fallback styling. The classic padding-bottom hack provides compatibility for older browsers:
/* Baseline styles that work everywhere */
.video-container {
height: 0;
padding-bottom: 56.25%; /* 16:9 aspect ratio fallback */
position: relative;
}
/* Enhancement for modern browsers */
@supports (aspect-ratio: 16 / 9) {
.video-container {
height: auto;
aspect-ratio: 16 / 9;
padding-bottom: 0;
}
}
Pattern 2: CSS Grid with Float Fallback
CSS Grid is a high-impact feature that always warrants explicit fallbacks. This pattern ensures your layout works even in browsers that predate grid support. For more on CSS Grid fundamentals, see our guide on Grid and Flexbox layouts:
/* Baseline using float layout */
.grid-item {
float: left;
width: 31.33%;
margin: 1%;
}
/* Enhancement using CSS Grid */
@supports (display: grid) {
.grid-item {
float: none;
width: auto;
margin: 0;
}
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2%;
}
}
Pattern 3: Logical Properties
Logical properties like margin-inline and padding-block provide a great example of combining multiple @supports queries. These properties are part of the modern CSS logical properties specification that enables writing direction-agnostic styling:
/* Baseline with physical properties */
.element {
margin-left: auto;
margin-right: auto;
padding-top: 1rem;
padding-bottom: 1rem;
}
/* Enhancement with logical properties */
@supports (margin-inline: auto) {
.element {
margin-inline: auto;
}
}
@supports (padding-block: 1rem) {
.element {
padding-block: 1rem;
}
}
Best Practices for Production
1. Define Baseline Styles First
Always write styles that work without any feature detection. The baseline should provide a functional experience for all users, then enhance for capable browsers:
/* Baseline: works everywhere */
.button {
display: inline-block;
padding: 0.75rem 1.5rem;
border: 2px solid #0066cc;
background: #0066cc;
color: white;
}
/* Enhancement: uses modern features when supported */
@supports (backdrop-filter: blur(10px)) {
.button {
background: rgba(0, 102, 204, 0.85);
backdrop-filter: blur(10px);
}
}
2. Consider Feature Impact
| Impact Level | Examples | Recommendation |
|---|---|---|
| Low | accent-color, overscroll-behavior | Can often skip @supports |
| Medium | aspect-ratio, scroll-margin | Good candidates for @supports |
| High | grid layout, container queries | Always use @supports with fallbacks |
3. Test Across Browsers
Always verify your @supports queries work as expected across target browsers. Use browser dev tools to inspect computed styles, test on actual devices when possible, and use resources like caniuse.com for support data. Our web development services team can help you establish comprehensive testing workflows.
4. Group Related Features
Keep queries simple and group related features together for efficient CSS parsing:
/* Efficient: single query, multiple rules */
@supports (display: grid) {
.card, .gallery, .dashboard {
display: grid;
gap: 1rem;
}
}
@supports in Next.js Projects
CSS Modules
The most straightforward approach in Next.js uses CSS Modules or global CSS, which work seamlessly with @supports:
/* globals.css or Button.module.css */
.card {
display: block;
}
@supports (display: grid) {
.card {
display: grid;
gap: 1rem;
}
}
Build Tool Integration
Build tools like PostCSS enhance @supports usage with plugins that help manage vendor prefixes and future CSS features:
- postcss-preset-env: Enables future CSS features with automatic polyfilling
- Autoprefixer: Handles vendor prefixes automatically
- LightningCSS: Includes Autoprefixer, minification, and CSS transpilation
Styled Components
When using CSS-in-JS libraries like styled-components in Next.js, @supports queries work at the CSS level:
import styled from 'styled-components';
const GridContainer = styled.div`
display: block;
@supports (display: grid) {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1rem;
}
`;
Performance Characteristics
The @supports at-rule is evaluated by the browser's CSS engine during stylesheet parsing. This evaluation is fast because browsers optimize CSS parsing extensively, results are cached across stylesheet processing, and there's no runtime JavaScript overhead since it's declarative.