What Is the CSS @supports Feature Query?
The CSS @supports feature query is a conditional rule
that allows developers to test whether a web browser supports specific
CSS property-value pairs or selectors before applying corresponding
styles. By enabling native feature detection directly within
stylesheets, @supports provides a reliable foundation for
progressive enhancement, allowing modern styling techniques to be
implemented without breaking layouts on older or non-compliant
browsers.
How the @supports Rule
Works
Often referred to as a "feature query," the @supports
at-rule tests browser capabilities at runtime. If the browser parses and
supports the specified declaration, the enclosed CSS block executes. If
the declaration is unsupported, the browser skips the entire block.
This mechanism avoids the need for external JavaScript feature-detection libraries (such as Modernizr) for purely visual features, improving performance and keeping style-related logic inside CSS.
Basic Syntax and Examples
The syntax of @supports consists of the
@supports keyword, a condition wrapped in parentheses
containing a CSS declaration, and a block of rules to apply if the
condition evaluates to true.
@supports (display: grid) {
.container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
}In this example, the grid layout styles apply only if the browser
supports display: grid.
Combining Conditions with Logical Operators
Feature queries support logical operators to create sophisticated
detection logic: and, or, and
not.
The and Operator
The and operator requires all specified declarations to
be supported.
@supports (display: flex) and (backdrop-filter: blur(10px)) {
.card {
display: flex;
backdrop-filter: blur(10px);
background-color: rgba(255, 255, 255, 0.5);
}
}The or Operator
The or operator checks whether at least one of the
conditions is supported, which is useful when dealing with
vendor-prefixed properties or alternative implementations.
@supports (background: -webkit-named-image(i)) or (aspect-ratio: 16 / 9) {
.video-container {
aspect-ratio: 16 / 9;
}
}The not Operator
The not operator inverts the logic, applying styles only
when a feature is unsupported.
@supports not (display: grid) {
.container {
float: left;
width: 100%;
}
}When combining not with other operators, parentheses
must explicitly define precedence:
@supports (display: flex) and (not (gap: 1rem)) {
.flex-item {
margin-right: 1rem;
}
}Testing for Selector Support
Beyond property-value declarations, modern implementations of
@supports allow checking whether a browser recognizes
specific CSS selectors using the selector() function.
@supports selector(:has(> .child)) {
.parent:has(> .child) {
border: 2px solid blue;
}
}This prevents complex relational selectors from failing silently or causing unexpected behavior in legacy rendering engines.
Progressive Enhancement Strategy
The recommended practice with @supports is to build a
solid baseline layout using universally supported CSS outside of any
@supports block, then layer advanced styling inside an
@supports query.
/* Base styles for all browsers */
.gallery {
display: block;
}
.gallery-item {
display: inline-block;
width: 30%;
margin: 1%;
}
/* Enhanced layout for modern browsers */
@supports (display: grid) and (gap: 1rem) {
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 1rem;
}
.gallery-item {
width: auto;
margin: 0;
}
}By structuring stylesheets this way, older user agents render a functional baseline, while newer browsers receive a richer visual experience without dependency overhead.