The @supports CSS at-rule lets you specify declarations that depend on a browser's support for one or more specific CSS features. This is called a feature query. The rule may be placed at the top level of your code or nested inside any other conditional group at-rule.

@supports (display: grid) {
  div {
    display: grid;
  }
}
@supports not (display: grid) {
  div {
    float: right;
  }
}

In JavaScript, @supports can be accessed via the CSS object model interface CSSSupportsRule.

Syntax

The @supports at-rule associates a block of statements with a supports condition. The supports condition consists of one or more name-value pairs combined by conjunctions (and), disjunctions (or), and/or negations (not). Precedence of operators can be defined with parentheses.

Declaration syntax

The most basic supports condition is a simple declaration (a property name followed by a value, separated by a colon). The declaration must be surrounded by parentheses. The following example returns true if the browser's transform-origin property considers 5% 5% valid:

@supports (transform-origin: 5% 5%)

Function syntax

The second basic supports condition is a supports function, the syntax for these is supported by all browsers, but the functions themselves are still being standardized.

selector()

Tests if the browser supports the tested selector syntax. The following example returns true if the browser supports the child combinator:

@supports selector(A > B)

The not operator

The not operator can precede any expression to create a new expression, resulting in the negation of the original one. The following example returns true if the browser's transform-origin property doesn't consider 10em 10em 10em valid:

@supports not (transform-origin: 10em 10em 10em)

As with any operator, the not operator can be applied to a declaration of any complexity. The following examples are both valid:

@supports not (not (transform-origin: 2px))
@supports (display: grid) and (not (display: inline-grid))

Note: There is no need to enclose the not operator between two parentheses at the top level. To combine it with other operators, like and and or, the parentheses are required.

The and operator

The and operator creates a new expression from the conjunction of two shorter expressions. It returns true only if both of the shorter expressions are also true. The following example returns true if and only if the two shorter expressions are simultaneously true:

@supports (display: table-cell) and (display: list-item)

Multiple conjunctions can be juxtaposed without the need of more parentheses. The following are both equivalent:

@supports (display: table-cell) and (display: list-item) and (display:run-in)
@supports (display: table-cell) and ((display: list-item) and (display:run-in))

The or operator

The or operator creates a new expression from the disjunction of two shorter expressions. It returns true if one or both of the shorter expressions is also true. The following example returns true if at least one of the two shorter expressions is true:

@supports (transform-style: preserve) or (-moz-transform-style: preserve)

Multiple disjunctions can be juxtaposed without the need of more parentheses. The following are both equivalent:

@supports (transform-style: preserve) or (-moz-transform-style: preserve) or 
          (-o-transform-style: preserve) or (-webkit-transform-style: preserve)

@supports (transform-style: preserve-3d) or ((-moz-transform-style: preserve-3d) or
          ((-o-transform-style: preserve-3d) or (-webkit-transform-style: preserve-3d)))

Note: When using both and and or operators, the parentheses must be used to define the order in which they apply. Otherwise, the condition is invalid and the whole rule is ignored.

Formal syntax

@supports <supports-condition> {
  <group-rule-body>
}

Examples

Testing for the support of a given CSS property

@supports (animation-name: test) {
  … /* CSS applied when animations are supported without a prefix */
  @keyframes { /* Other at-rules can be nested inside */
    …
  }
}

Testing for the support of a given CSS property or a prefixed version

@supports ((perspective: 10px) or (-moz-perspective: 10px) or (-webkit-perspective: 10px) or
         (-ms-perspective: 10px) or (-o-perspective: 10px)) {
  … /* CSS applied when 3D transforms, prefixed or not, are supported */
}

Testing for the non-support of a specific CSS property

@supports not ((text-align-last: justify) or (-moz-text-align-last: justify)) {
  … /* CSS to provide fallback alternative for text-align-last: justify */
}

Testing for the support of custom properties

@supports (--foo: green) {
  body {
    color: var(--varName);
  }
}

Testing for the support of a selector (eg. :matches())

This is an experimental technology
Check the Browser compatibility table carefully before using this in production.

/* This rule won't be applied in browsers which don't supports :matches() */
:matches(ul, ol) > li {
  … /* CSS appllied when the :matches(…) selector is supported */
}

@supports not selector(:matches(a, b)) {
  /* Fallback for when :matches() is unsupported */
  ul > li,
  ol > li {
    … /* The above expanded for browsers which don't support :matches(…) */
  }
}

@supports selector(:matches(a, b)) {
  /* This rule needs to be inside the @supports block, otherwise it might
     be partially applied in browsers which don't support :matches(…) */
  :matches(ul, ol) a,
  details > summary {
    … /* CSS appllied when the :matches(…) selector is supported */
  }
}

Specifications

Specification Status Comment
Unknown
The definition of '@supports' in that specification.
Unknown Adds the selector() function.
CSS Conditional Rules Module Level 3
The definition of '@supports' in that specification.
Candidate Recommendation Initial definition.

Browser compatibility

Update compatibility data on GitHub
DesktopMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidEdge MobileFirefox for AndroidOpera for AndroidiOS SafariSamsung Internet
Basic supportChrome Full support 28Edge Full support 12Firefox Full support 22
Full support 22
No support 17 — ?
Disabled
Disabled From version 17: this feature is behind the layout.css.supports-rule.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
IE No support NoOpera Full support 12.1Safari Full support 9WebView Android Full support YesChrome Android Full support 28Edge Mobile Full support YesFirefox Android Full support 22
Full support 22
No support 17 — ?
Disabled
Disabled From version 17: this feature is behind the layout.css.supports-rule.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
Opera Android Full support 12.1Safari iOS Full support 9Samsung Internet Android Full support Yes
selector()
Experimental
Chrome No support NoEdge No support NoFirefox Full support 64
Disabled
Full support 64
Disabled
Disabled From version 64: this feature is behind the layout.css.supports-selector.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
IE No support NoOpera No support NoSafari No support NoWebView Android No support NoChrome Android No support NoEdge Mobile No support NoFirefox Android Full support 64
Disabled
Full support 64
Disabled
Disabled From version 64: this feature is behind the layout.css.supports-selector.enabled preference (needs to be set to true). To change preferences in Firefox, visit about:config.
Opera Android No support NoSafari iOS No support NoSamsung Internet Android No support No

Legend

Full support  
Full support
No support  
No support
Experimental. Expect behavior to change in the future.
Experimental. Expect behavior to change in the future.
User must explicitly enable this feature.
User must explicitly enable this feature.

See also