File Under: CSS, Web Standards

Use Tomorrow’s Web Standards Today With CSS ‘@Supports’

Woolly, the CSS sheep.

Using CSS 3 on the web today means that, inevitably, some browsers won’t be able to display some elements of your design. Hopefully you’re using progressive enhancement so that your pages still function in less-capable browsers, which might not understand all those fancy transform rules.

For more complex projects progressive enhancement might even mean turning to a feature detection library like Modernizr, which will detect and apply CSS classes based on the current browser’s capabilities.

Modernizr is great when you need it, but did you know that soon the browser itself will be able to give you the same information?

Both Opera 12.10 and Firefox 19 (currently in the Aurora channel) support native CSS feature detection through the CSS @supports rule. CSS @supports offers the same capabilities of Modernizr — selectively applying CSS based on what the current browser supports — but it does it through much faster native code. Even better, because browsers that don’t support @supports will just ignore it, you can start using it today.

Opera Software’s Chris Mills recently posted a nice intro to using @supports which you should read for more details, but here’s an example to illustrate the basic idea:

@supports ( box-shadow: 2px 2px 2px black ) {
    .my-element {
        box-shadow: box-shadow: 2px 2px 2px black;
    }
}

The code above uses @supports to check for support for the box-shadow property and then applies a box shadow to browsers that will display it. Of course since many of the features you’d likely be detecting are still prefixed, a more complete example (pulled from the W3C’s @supports page) would look like this:

@supports ( box-shadow: 2px 2px 2px black ) or
          ( -moz-box-shadow: 2px 2px 2px black ) or
          ( -webkit-box-shadow: 2px 2px 2px black ) or
          ( -o-box-shadow: 2px 2px 2px black ) {
    .outline {
        color: white;
        -moz-box-shadow: 2px 2px 2px black;
        -webkit-box-shadow: 2px 2px 2px black;
        -o-box-shadow: 2px 2px 2px black;
        box-shadow: 2px 2px 2px black; /* unprefixed last */
    }
}

Now we’re checking for not just box-shadow but any vendor-prefixed versions of it as well. We’re also not just applying box-shadow, but also changing the outline color to white, which (assuming a white background) would not be good to do in browsers that don’t support box-shadow since it would make the outline invisible to the user.

As you can see @supports is pretty handy for progressive enhancement and it avoids the overhead of loading a JavaScript library like Modernizr. CSS @supports also works with operators like not and or so that you could write a rule that says the opposite of what we did above. In other words, detect that the current browser doesn’t support box-shadow and do something else.

CSS @supports gets even more powerful when you start chaining @support rules together, which is what Mills does in his post on the Opera Dev center, detecting for animations and transforms to serve one thing to browsers that support 3D transforms, one to those that only understand 2D transforms and a third to those that don’t support transforms at all.

So should you ditch Modernizr and go with @supports? Probably not just yet, but soon. First off, if you’re using Modernizr for more than just CSS detection then obviously stick with it. But, as Opera’s Bruce Lawson notes in a follow-up to Mills’ post, “the reason to use @supports over Modernizr is performance; functionality that’s built into the browser will always be faster than adding it in script.” Getting rid of Modernizr would also mean eliminating an external dependency, which saves an HTTP request as well.

In fact Modernizr itself plans to defer to @supports in future releases. If you’d like to have the best of both worlds today, what you need to do is first detect for @supports and then if it’s not available load Modernizr. See Lawson’s post for a code snippet that does just that.