CSS has evolved dramatically, with new features landing in browsers at an unprecedented pace. The @supports at-rule, commonly known as feature queries, gives developers a powerful mechanism to detect browser support for CSS properties and values before applying styles. This capability is essential for building resilient, future-proof websites that leverage modern CSS while maintaining compatibility with older browsers. Rather than relying on brittle browser detection or vendor prefix strategies, feature queries enable a clean, standards-based approach to progressive enhancement--delivering enhanced experiences to capable browsers while ensuring baseline functionality everywhere. For teams building with modern frameworks like Next.js, where performance and SEO are paramount, understanding @supports is crucial for optimizing the critical rendering path without sacrificing modern CSS capabilities.
Understanding CSS Feature Queries
Feature queries are conditional group rules that test whether the user agent supports or does not support one or more CSS features, such as CSS properties and property values. The @supports at-rule lets you specify CSS declarations that depend on a browser's support for CSS features, and using this at-rule is commonly called a feature query. The rule must be placed at the top level of your code or nested inside any other conditional group at-rule. MDN Web Docs - @supports
Why Feature Queries Matter
In the modern web development landscape, browsers release new CSS features regularly. Container queries, cascade layers, and custom media queries represent just a fraction of the innovations transforming how we build layouts. However, these features don't arrive simultaneously across all browsers, and users on older browser versions still constitute a meaningful portion of web traffic for many sites.
Feature queries solve a fundamental challenge: how to use new CSS capabilities without breaking the experience for users on browsers that haven't implemented those features yet. Rather than serving identical styles to all users--which means everyone gets the baseline experience regardless of their browser's capabilities--or resorting to user-agent sniffing (an error-prone practice), feature queries allow you to write conditional CSS based on actual feature support.
This approach aligns perfectly with the performance-first mindset required for modern web development. Rather than shipping polyfills or JavaScript-based fallbacks that add script weight and delay rendering, feature queries operate purely at the CSS level--enabling the browser to parse and apply styles efficiently without additional runtime overhead.
Basic Syntax and Declaration Conditions
The @supports At-Rule
The @supports at-rule consists of a supports condition followed by a block of CSS declarations. The basic syntax follows this pattern:
@supports (<supports-condition>) {
/* If the condition is true, use the CSS in this block. */
}
The supports condition can evaluate to true or false based on whether the browser supports the specified CSS feature. When the condition is true, the browser parses and applies the CSS within the block. When false, the entire block is ignored.
Declaration Syntax
The declaration syntax checks if a browser supports the specified property-value pair. The declaration must be surrounded by parentheses:
@supports (transform-origin: 5% 5%) {
/* Apply styles only if transform-origin with percentage values is supported */
}
You can test any CSS property-value combination. The browser evaluates whether it recognizes and can properly parse the declaration. For widely-supported properties like display: flex, the condition returns true in virtually all modern browsers:
@supports (display: flex) {
.flex-container {
display: flex;
gap: 1rem;
}
}
The value part of the property-value pair matters when testing for new or experimental values. All browsers support color: red--this dates back to CSS1. However, newer values like color: AccentColor or relative color syntax may not be universally supported. MDN Web Docs - Using feature queries Feature queries enable testing property and value pairs, meaning developers can detect support for specific values, not just properties.
Testing Property Existence
When all you want is to check that the browser supports a particular property, any valid value will do for the test. This is useful for properties with numerous potential values:
@supports (grid-template-columns: subgrid) {
/* Grid subgrid is supported */
.nested-grid {
grid-template-columns: subgrid;
}
}
The browser doesn't need to evaluate whether it would use subgrid specifically--it only needs to confirm it understands the grid-template-columns property well enough to parse the declaration.
Combining Conditions with Logical Operators
Using the AND Operator
You may need to test support for more than one property in your feature query. MDN Web Docs - Using feature queries Conditions can be combined by conjunctions using the and keyword:
@supports (display: grid) and (shape-outside: circle()) {
.floated-element {
float: left;
shape-outside: circle(50%);
}
.grid-layout {
display: grid;
}
}
The rule will only return true if both display: grid and shape-outside: circle() are supported by the browser.
Using the OR Operator
You can also use or to apply CSS only if one or more declarations are supported. This is particularly useful when a feature has vendor-prefixed alternatives:
@supports (font-smooth: always) or (-webkit-font-smoothing: antialiased) {
body {
-webkit-font-smoothing: antialiased;
font-smooth: always;
}
}
This pattern ensures smooth fonts regardless of which syntax the browser recognizes.
Using the NOT Operator
In addition to asking the browser if it supports a feature, you can test for the opposite by adding the not keyword:
@supports not (backdrop-filter: blur(10px)) {
.card {
/* Fallback for browsers without backdrop-filter */
background-color: #f5f5f5;
}
}
The CSS inside a not query will run if the browser does not support the specified feature. This enables fallback styling for older browsers.
Operator Precedence
The precedence of operators can be defined with parentheses. Complex conditions require explicit grouping:
@supports ((display: grid) and (grid-template-rows: subgrid)) or (display: flex) {
/* Apply when either grid with subgrid is supported OR flexbox is available */
}
Function Syntax: Beyond Property Values
The selector() Function
The function syntax checks if a browser supports values or expressions within the function. MDN Web Docs - @supports The selector() function evaluates whether a browser supports a specific selector syntax:
@supports selector(h2 > p) {
/* Apply if the browser understands h2 > p (child combinator) */
}
@supports selector(.card:has(.featured)) {
.card:has(.featured) {
border: 2px solid gold;
}
}
This capability becomes valuable when testing for selector support, particularly for newer pseudo-elements and pseudo-classes. The CSS Conditional Rules Module Level 4 extends @supports to allow testing for supported selectors. W3C CSS Conditional Rules Module Level 4
The font-tech() Function
This function checks if a browser supports the specified font technology for layout and rendering. The following example returns true and applies the CSS style if the browser supports the COLRv1 font technology:
@supports font-tech(color-COLRv1) {
.colorful-text {
font-family: "MyColorFont";
color: transparent;
background: linear-gradient(45deg, red, blue);
background-clip: text;
}
}
The table below describes the font technologies that can be queried using the font-tech() function:
| Technology | Description |
|---|---|
color-colrv0 | Multi-colored glyphs via COLR version 0 table |
color-colrv1 | Multi-colored glyphs via COLR version 1 table |
color-svg | SVG multi-colored tables |
features-opentype | OpenType GSUB and GPOS tables |
features-aat | TrueType morx and kerx tables |
variations | Font variations in TrueType and OpenType fonts |
palettes | Font palettes by means of font-palette |
The font-format() Function
This function checks if a browser supports the specified font format for layout and rendering:
@supports font-format(opentype) {
@font-face {
font-family: "MyFont";
src: url("myfont.woff2") format("woff2");
}
}
The available formats that can be queried include:
| Format | Description | File Extensions |
|---|---|---|
opentype | OpenType | .ttf, .otf |
woff | WOFF 1.0 | .woff |
woff2 | WOFF 2.0 | .woff2 |
collection | OpenType Collection | .otc, .ttc |
Practical Applications and Use Cases
Layout Enhancement with CSS Grid and Flexbox
One of the most common applications of feature queries is progressively enhancing layouts. Start with a float-based or inline-block layout that works everywhere, then enhance to grid or flexbox for capable browsers:
/* Baseline layout for all browsers */
.gallery {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.gallery-item {
flex: 1 1 300px;
}
/* Enhanced grid layout for browsers that support it */
@supports (display: grid) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
}
.gallery-item {
flex: none; /* Reset flexbox fallback */
}
}
Backdrop Filter and Visual Effects
The backdrop-filter property, which applies graphical effects to the area behind an element, has excellent support in modern browsers but lacks support in older ones:
.modal-backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
@supports (backdrop-filter: blur(10px)) {
.modal-backdrop {
backdrop-filter: blur(10px);
background-color: rgba(0, 0, 0, 0.3);
}
}
This pattern lets you use the visually appealing blur effect where supported while maintaining legibility through higher opacity in unsupported browsers.
Container Queries
Container queries represent one of the most significant additions to CSS in recent years, enabling responsive components based on their container's size rather than the viewport. Feature queries provide the mechanism to progressively enhance components:
/* Baseline responsive behavior using media queries */
.card {
padding: 1rem;
}
@media (min-width: 640px) {
.card {
padding: 1.5rem;
}
}
/* Container query enhancement */
@supports (container-type: inline-size) {
.card-container {
container-type: inline-size;
}
@container (min-width: 400px) {
.card {
padding: 2rem;
display: flex;
gap: 1rem;
}
}
}
CSS Custom Properties and Dynamic Theming
Feature queries can test for custom property support, enabling progressive enhancement of dynamic theming systems:
/* Baseline static styles */
:root {
--primary-color: #0066cc;
--text-color: #333;
}
.button {
background-color: var(--primary-color);
color: white;
padding: 0.75rem 1.5rem;
}
/* Enhanced theming for browsers with custom property support */
@supports (--custom-properties: true) {
:root {
--primary-color: oklch(55% 0.25 250);
--text-color: oklch(30% 0.02 280);
}
@media (prefers-color-scheme: dark) {
:root {
--primary-color: oklch(65% 0.25 250);
--text-color: oklch(90% 0.01 280);
}
}
}
Performance Considerations
CSS Parsing and Evaluation
Feature queries are evaluated during CSS parsing, which means they add minimal runtime overhead. The browser determines whether each @supports block applies before constructing the CSSOM (CSS Object Model), and unsupported blocks are simply not added to the stylesheet's rules. This is significantly more efficient than JavaScript-based feature detection, which requires script execution and DOM manipulation.
For performance-critical rendering paths, feature queries enable you to keep CSS parsing efficient while still delivering enhanced experiences. The browser's CSS parser is highly optimized, and feature query evaluation is a trivial addition to that process.
Critical Rendering Path Optimization
When building performance-focused websites with frameworks like Next.js, the critical rendering path--the sequence of steps the browser takes to convert HTML, CSS, and JavaScript into rendered pixels--directly impacts Core Web Vitals metrics like Largest Contentful Paint and Cumulative Layout Shift. This is a critical consideration for effective SEO strategies that prioritize user experience signals.
Feature queries support critical path optimization by keeping baseline styles minimal while enabling enhanced layouts through efficient CSS conditional loading. Rather than requiring separate stylesheets for different browser capability levels (which would multiply HTTP requests), feature queries keep all styles in a single sheet with conditional application.
Minimizing Unnecessary Rules
Best practice involves structuring feature queries to minimize complexity. Deeply nested feature queries or excessive logical operator combinations can make stylesheets harder to maintain and may increase parsing time marginally. Consider these guidelines:
Keep feature queries at the top level of stylesheets or within the relevant module, not deeply nested within component-specific rules. This organization makes it easier to understand the progressive enhancement strategy and reduces specificity conflicts.
Group related feature enhancements together rather than scattering them throughout the stylesheet. A well-organized feature query section at the beginning or end of the stylesheet provides a clear progressive enhancement contract.
Test for features you actually intend to use. Feature queries for hypothetical future browser support add complexity without immediate benefit.
Best Practices for Feature Query Implementation
Start with Baseline Styles
Always begin with styles that work everywhere, then enhance progressively. This "mobile-first" approach to CSS capabilities ensures functional experiences regardless of browser capability:
/* Foundation layer - works in all browsers */
.component {
/* essential layout and styling */
}
@supports (display: flex) {
/* Enhanced layout for flex-capable browsers */
.component {
display: flex;
}
}
@supports (display: grid) {
/* Grid enhancement for grid-capable browsers */
.component {
display: grid;
}
}
Use @supports for Enhancement, Not Conditionals
Feature queries should enhance experiences, not serve as primary conditional logic. Avoid patterns where the baseline experience is insufficient for users without the featured capability. Every user should have a functional, complete experience--feature queries layer improvements on top.
Combine with Media Queries Thoughtfully
Feature queries and media queries serve different purposes and can be combined effectively:
/* Mobile-first baseline */
.layout {
display: block;
}
/* Tablet enhancement */
@media (min-width: 768px) {
.layout {
display: flex;
}
}
/* Grid enhancement for capable browsers at tablet+ sizes */
@supports (display: grid) {
@media (min-width: 768px) {
.layout {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
}
}
Document Your Progressive Enhancement Strategy
For complex projects with multiple enhancement layers, consider documenting the feature query strategy. A comment block at the top of stylesheets or a dedicated documentation file helps team members understand the baseline expectations and enhancement layers.
Common Patterns and Anti-Patterns
Effective Patterns
Nested feature queries for progressive enhancement:
.component {
/* Base styles */
}
@supports (display: flex) {
.component {
display: flex;
}
@supports (gap: 1rem) {
.component {
gap: 1rem;
}
}
}
Testing for vendor-prefixed features with or:
@supports (-webkit-backdrop-filter: blur(10px)) or (backdrop-filter: blur(10px)) {
.glass {
backdrop-filter: blur(10px);
}
}
Using not for fallback strategies:
@supports not (backdrop-filter: blur(10px)) {
.glass {
background-color: rgba(255, 255, 255, 0.9);
}
}
Anti-Patterns to Avoid
Feature queries that hide essential styles: Never place styles essential for basic functionality inside a feature query. Users on browsers that don't support the feature should still have a complete, usable experience.
Overly broad feature queries: Avoid testing for multiple unrelated features together unless the styles genuinely require all of them. Separate feature queries provide more granular control and clearer intent.
Testing for deprecated vendor prefixes:
While or patterns can include vendor prefixes for compatibility, avoid testing for prefixes that no longer provide meaningful coverage. Modern browsers have largely standardized, and maintaining long vendor prefix lists adds complexity without benefit.
Frequently Asked Questions
What browsers support @supports?
The @supports at-rule has been widely available across browsers since September 2015. It is supported in all major browsers including Chrome, Firefox, Safari, and Edge. The small percentage of users on browsers that don't support @supports (primarily very old versions of Internet Explorer) will simply get the baseline styles outside the feature queries.
When should I use feature queries vs. media queries?
Feature queries test whether the browser engine supports specific CSS capabilities, while media queries test characteristics of the viewing environment like viewport size or device characteristics. Use feature queries for progressive enhancement based on CSS support, and media queries for responsive design based on device or viewport conditions.
Do feature queries impact page performance?
Feature queries add minimal runtime overhead because they are evaluated during CSS parsing, before the CSSOM is constructed. The browser's CSS parser handles this efficiently, making feature queries significantly more performant than JavaScript-based feature detection approaches.
Can I nest feature queries?
Yes, feature queries can be nested within other feature queries or within @media blocks. This enables sophisticated progressive enhancement strategies where you test for a base capability, then further test for related enhancements within that context.
What is the difference between @supports and Modernizr?
@supports is a native CSS feature detection mechanism built into browsers, while Modernizr is a JavaScript library that detects HTML5 and CSS3 features. Feature queries are more efficient for CSS-based detection, while JavaScript detection is useful when you need to conditionally load scripts or modify DOM elements based on feature support.
Sources
- MDN Web Docs - @supports Reference - Official documentation for the CSS @supports at-rule
- MDN Web Docs - Using Feature Queries - Progressive enhancement implementation guide
- CSS Conditional Rules Module Level 4 - W3C - Official W3C specification for @supports extensions