How to use the @supports rule in your CSS

Have you ever used some form of CSS feature detection such as Modernizr to differentiate your CSS's behaviour based on whether a feature is supported? I bet most of you have. Although the cascading nature of CSS lets us provide fallbacks for many CSS features just by writing multiple declarations, sometimes we need more granular control over what is applied when some of our cutting edge bling isn't there.

Consider border-image. When it's unsupported, we usually want to provide a fallback background and a different border, which shouldn't apply when border-image applies. Another common case is new layout modules (Flexbox, Grid Layout and Regions); when they aren't available, we need to code an alternative layout using properties that could conflict with these technologies, which means they can't co-exist.

Fortunately, the CSS WG designed an elegant and pure CSS solution a while back called the @supports rule. With this rule, the border-image example would be written like:

.foo {
    border: 15px solid transparent;
    border-image: url(fancyborders.png) 33%;

@supports not (border-image: url(foo.png) 33%) {
    .foo {
        border: 3px solid rgba(0,0,0,.3);
        background: url(alternative-bg.png) beige;

This is called a 'feature query' , which is similar to a media query. In practice, you'll want to check for prefixed versions as well:

@supports not (border-image: url(foo.png) 33%)
          or (-moz-border-image: url(foo.png) 33%)
or (-webkit-border-image: url(foo.png) 33%) { ...

Besides or, and and not, operators are available, allowing for any kind of complex boolean logic. These rules can be nested, which greatly simplifies your code when using many complex feature queries.

There's a catch. It's unwise to use @supports for features that browsers supported before supporting @supports itself. Therefore, we cannot use it for many things yet. However, it's already supported by Firefox 22+, Chrome 28+ and Opera 12.1+. If IE 11 and Safari 7 also support it, we can start using it for features introduced at or after these versions.

The CSS WG also realised that using prefixes for @supports would kind of defeat the purpose (as authors would have to write multiple rules several times). Therefore, every browser that supports @supports is doing so without any prefix. There is no such thing as @-webkit-supports. When browsers were unsure about their implementations, they hid it behind a flag, like Firefox did in versions 17-27.

You may be thinking that this is great for CSS, but it doesn't help you detect CSS features through JavaScript, which is sometimes needed. Fortunately, it comes with its own elegant JavaScript API as well: CSS.supports() . It's used like so:

if (CSS.supports('border-image', 'url(foo.png) 33%')) { ... }

This function is also easy to polyfill, so it can be made available in browsers that haven't caught up. Hopefully in the future we'll be able to detect support for other CSS features, such as @rules and selectors, rather than just properties and values.

Words: Lea Verou

Lea Verou previously worked as a developer advocate at W3C and currently spends her days writing & designing her first book, titled CSS Secrets, which is due to be published with O'Reilly in 2014

This article originally appeared in net magazine issue 248.

Liked this? Read these!