Thinking Ahead: Native CSS Feature Detection

Making The Web Faster With SPDY

Developing with progressive enhancement is not only a best practice, it’s necessary given the complexity of today’s websites and applications. We should never be sacrificing accessibility for convenience, so minimizing dependency on CSS3 features is important and, as a last resort, we need some form of feature detection for providing fallbacks.

The most common CSS feature detection methods require JavaScript. Modernizr, for example, is a popular detection library that checks support for CSS3 features (among other things). Some developers also write their own custom JavaScript tests.

Feature detection is about to become more streamlined, as CSS has a powerful new conditional rule that’s recently gained browser support. This is exciting news because we’re able to test the support of any CSS feature and provide the necessary fallbacks directly in the CSS.

The @supports Rule

CSS has built-in graceful degradation; if a browser doesn’t support a property or value, it simply ignores it. And if we include a fallback property that’s supported, nothing breaks. @supports drives this concept further by setting conditions based on browser support.

@supports is like a media query––it’s actually a feature query. A browser tests whether it can use certain properties if supported or ignore them if not. This means that soon we won’t need to rely on JavaScript for feature detection, so it will be easier than ever to use the latest CSS features and set fallback solutions for unsupported browsers.

Syntax

The syntax is similar to a media query, but instead of a media feature, we set a CSS declaration as the condition. The browser executes the styles inside the rule based on that condition.

For instance, the following transition is applied to .box only if the browser supports CSS transitions.

@supports (transition: .5s) {
  .box { transition: .5s; }
}

Operators

Like media queries, @supports has three operators that can test for support in different ways.

not

The not operator checks if the browser has no support for the CSS property. This is especially useful when using new layout features like flexbox, because our layout doesn’t have to be chained to flexbox support.

@supports not (display: flex) {
  .box { display: inline-block; width: 25%; }
}

If flexbox is not supported, the browser will apply the inline-block and width values to .box instead.

and

With and, the condition is true only if every expression is true. This way we can test for multiple features at once.

@supports (display: flex) and (transition: .5s) {
  .box { display: flex; transition: .5s; }
}

If flexbox and transitions are supported, the browser will apply the styles defined in the rule. If not, the browser simply ignores the entire rule.

or

With or, the expression is true if one or all the expressions defined are also true. This operator is useful for vendor-prefixed properties.

@supports (-webkit-transform: rotate(-25deg)) or
          (   -moz-transform: rotate(-25deg)) or
          (    -ms-transform: rotate(-25deg)) or
          (        transform: rotate(-25deg)) {
   .box {
     -webkit-transform: rotate(-25deg)
        -moz-transform: rotate(-25deg)
         -ms-transform: rotate(-25deg)
             transform: rotate(-25deg)
   }
}

Final Thoughts

The not operator might be @supports most useful feature because it’s the closest method to using JavaScript for feature detection and fallbacks.

Writing those extra CSS declarations may seem redundant––like code bloat. But keep in mind that feature detection functionality that’s native to the browser will perform faster than JavaScript.

We can start using @supports today, as it works in Chrome 28, Firefox 22, and Opera 12.1. It’s still too soon to abandon Modernizr altogether, but it’s worth noting that they’ve added a new detect that defers to the @supports rule in our style sheet if the browser supports it.

Free Workshops

Watch one of our expert, full-length teaching videos. Choose from HTML, CSS or WordPress.

Start Learning

Guil Hernandez

Guil is the front-end design teacher at Treehouse. You can follow Guil on Twitter at @guilh.

Comments

11 comments on “Thinking Ahead: Native CSS Feature Detection

  1. pretty cool. Seems like SASS or LESS could help lessen the code bloat you refer to a bit.

  2. Surely if the browser doesn’t support something like transition then it’s not going to support @supports? This makes the ‘not’ operator not very useful. I’d suggest setting a default which is going to be used by old browsers, then adding the conditional CSS in case the browser does support it.

    • Currently, yes, that’s what we need to do. But the point is: CSS is evolving. So in the near future, when new features are introduced (CSS level 4 & beyond), we’ll have a more practical use for @supports. These days, @supports can really come in handy when using Flexbox.

  3. Great post. Looking forward to native detection integration. My hope is that as browsers move forward with new feature integration, there’s fallback systems (like this) put in place. Really moving forward, in this case, means maintaining graceful degradation AND new feature support.

  4. everybody knows which browsers DO NOT supports the `@supports{}` thing, so we can target them just with this way without even checking anything.

  5. The @supports syntax seems rather bloated to me. Essentially repeating the declaration in the test and then again as the actual style declaration. It would be more succinct if it were similar to the Modernizr syntax for tests.