Using feature queries
Feature queries are conditional group rules that test whether the user agent supports or doesn't support one or more CSS features, such as CSS properties and property values. Feature queries give web developers a way to test to see if a browser has support for a certain feature, and then provide CSS that will only run based on the result of that test. In this guide, you will learn how to implement progressive enhancement using feature queries.
Feature queries are created using the CSS at-rule@supports
(or thesupports()
function within@import
at-rules).
In this article
Syntax
CSS feature queries are part of theCSS conditional rules module, which also defines the media query@media
at-rule. Feature queries behave similarly tomedia queries. The difference is that with a media query, you are testing something about the environment in which the web page is running, whereas with feature queries you are testing browser support for CSS features.
A feature query consists of the@supports
at-rule followed by the support condition or asupports()
function and declaration parameter within an@import
at-rule declaration:
/* `@supports` at-rule */@supports <support-condition> { /* CSS rules to apply */}/* `supports()` function */@import url_to_import supports(<declaration>);
For example, we can apply a set of styles or import an entire stylesheet if the user-agent supportsred
as a valid value for the CSScolor
property:
/* `@supports` at-rule */@supports (color: red) { /* CSS rules to apply */}/* `supports()` function */@import "/css/styles.css" supports(color: red);
As another example, if you want to check if a browser supports therow-gap
property you would write the following feature query. It doesn't matter which value you use in a lot of cases: if all you want is to check that the browser supports this property, then any valid value will do.
<div> If your browser supports the row-gap property, the border will be dashed and text will be red.</div>
body { font: 1.2em / 1.5 sans-serif;}.box { border: 4px solid blue; color: blue; padding: 1em;}@supports (row-gap: 10px) { .box { border: 4px dashed darkgreen; color: red; }}
The value part of the property-value pair matters more if you are testing for new values of a particular property. All browsers supportcolor: red
: this dates back to CSS1. However, there are often additional values added to properties in CSS, likerelative colors, which may not be supported. Feature queries enable testing property and value pairs, meaning we can detect support for values.
Expanding on thecolor
property example above, here we check if the browser supports thecolor: AccentColor
declaration:
/* `@supports` at-rule */@supports (color: AccentColor) { /* CSS rules to apply */}/* `supports()` function */@import "/css/styles.css" supports(color: AccentColor);
In these examples, we've used feature queries to check if the user-agent supports a specific value of a CSS property, listing the single declaration within parenthesis. You can test for multiple property values or the lack of support.
Testing for lack of support
In addition to asking the browser if it supports a feature, you can test for the opposite by adding in thenot
keyword:
/* `@supports` at-rule with `not` */@supports not (property: value) { /* CSS rules to apply */}
The CSS inside the following example feature query will run if the browser does not supportrow-gap
.
<div> If your browser does not support row-gap, the content will be darkgreen with a dashed border.</div>
body { font: 1.2em / 1.5 sans-serif;}.box { border: 4px solid blue; color: blue; padding: 1em;}@supports not (row-gap: 10px) { .box { border: 4px dashed darkgreen; color: darkgreen; }}
Testing for more than one feature
You may need to test support for more than one property in your feature query. To do so, you can include a list of features to test for, separated byand
keywords:
/* multiple feature `@supports` at-rule */@supports (property1: value) and (property2: value) { /* CSS rules to apply */}
For example, if the CSS you want to run requires that the browser supports CSS Shapes and CSS grid, you could create a rule that tests browser support for both of these features. The following rule will only return true ifshape-outside: circle()
anddisplay: grid
are both supported by the browser.
<div> If your browser supports <code>display: grid</code> and <code>shape-outside: circle()</code>, the content will be darkgreen with a dashed border.</div>
body { font: 1.2em / 1.5 sans-serif;}.box { border: 4px solid blue; color: blue; padding: 1em;}@supports (display: grid) and (shape-outside: circle()) { .box { border: 4px dashed darkgreen; color: darkgreen; }}
Testing for at least one of multiple features
You can also useor
to apply CSS only if one or more declarations are supported:
/* any feature `@supports` at-rule */@supports (property1: value) or (property2: value) { /* CSS rules to apply */}
This can be particularly useful if a feature is vendor prefixed, as you can test for the standard property plus any vendor prefixes.
<div> The text and border will be green if your browser supports font smoothing.</div>
body { font: 1.2em / 1.5 sans-serif;}.box { border: 4px solid blue; color: blue; padding: 1em;}@supports (font-smooth: always) or (-webkit-font-smoothing: antialiased) { .box { border: 4px dashed darkgreen; color: darkgreen; }}
Additional feature query options
Feature queries are not limited to property-value pairs. You can includefont-tech()
,font-format()
, andselector()
functions in your feature queries to selectively apply CSS based on whether the user-agent supports a specified font technology, font format, or selector syntax, respectively.
For example, theselector()
function can be used to import a stylesheet for browsers that support a vendor-prefixed pseudo-element:
/* A `selector()` query within a `supports()` function */@import "/css/webkitShadowStyles.css" supports(selector(::-webkit-inner-spin-button));
Examples
>Browser support test
In this example, we check if the browser supports theAccentColor
<system-color>
and usedisplay: none
to change the default "not supported" message to a "supported" message if the color type is supported.
HTML
<p> Your browser does <span>not</span> support <code>AccentColor</code> as a color value.</p>
CSS
body { font: 1.2em / 1.5 sans-serif;}p { padding: 1em;}@supports (color: AccentColor) { p { color: green; border: 2px solid; } span { display: none; }}@supports not (color: AccentColor) { p { color: red; }}
Result
Limitations of feature queries
The@supports
rule tests to see if browsers can parse one or more property/value pairs, and therefore if they claim to support the associated feature(s). If the property/value pairs are understood by a browser it returns a positive response. Feature queries check that declarations are considered valid by a browser, but can't be used to check if it supports a feature properly without bugs or spec violations. Feature queries cannot test forpartial implementations.
Summary
Feature queries are a useful tool for progressively enhancing a site. They enable you to provide a good solution for all browsers, and an enhanced solution for browsers that support newer properties and values.
You don't need to use feature queries to start using new CSS features; CSS error handling means the browser simply ignores CSS it does not yet recognize. However, feature queries are a useful alternative to fallback declarations, and enable writing code once that can eventually be supported everywhere.