Since its arrival, browser support for CSS3 has been variable, making feature detection not just a good idea but best practice.
Although this detection is usually done with JavaScript, ideally it would be done within CSS which is where @supports comes in. CSS @supports allows us to have simpler and cleaner feature detection that doesn’t rely on other technologies, and works even if JavaScript is disabled.
Browser support
Unfortunately as with so many cool technologies, there is the issue of browser support with this rule, as older browsers do not support it, and even some new versions are lacking. At the time of writing, Chrome, Opera and Firefox mobile and desktop all support it, but the latest versions of Safari and Internet Explorer do not.
An alternative would be to use a polyfill to create support for the rule, but that means using JavaScript.
The @supports rule
The great thing about CSS is that it has pretty good degradation, which means that if something is not supported it won’t break your page, it will simply be ignored.
The idea behind @supports is to take this a step further. It allows you to write fallback code that will only be read if the preferred properties are not supported in a particular browser.
When creating a new @supports rule, you can see that the code is pretty similar to what you would see in a media query; even the operators are the same. It should look something like this:
@supports(property: value) {
/* Styles if condition is met */
}
If you want to test if a browser supports text-stroke for example, you would use the following simple code:
@supports(-webkit-text-stroke: 1px black) {
h1 {
-webkit-text-stroke: 1px black;
}
}
A browser that supports text-stroke will read what is inside the brackets, one that doesn’t support it won’t even try.
One of the operators used by the @supports rule is the not operator. This checks if a browser does not support a particular feature and the fallback code is placed inside the brackets. Using the text-stroke example you might use this to add a text shadow to create a similar look:
@supports not (-webkit-text-stroke: 1px black) {
h1 {
text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
}
}
Using the not operator here means that the code inside the brackets will only be read if the preferred feature is not supported. It works like an else statement for the conditional with no operator.
The or operator allows you to test more than one condition at a time, and will return true if any of them are met. This comes in very useful for properties that use different vendor prefixes for different browsers.
For example to test if transition is supported you might use the following:
@supports(transition: width 500ms) or (-webkit-transition: width 500ms) {
div {
transition: width 500ms;
transition: width 500ms;
}
}
A number of CSS properties require extra vendor prefixes and the or operator allows you to test for them at the same time. Only one needs to return true for the code inside the brackets to be read.
The final operator used by @supports is and, which tests more than one condition at a time returning true only if all of them are met. The syntax is similar to or:
@supports(border-radius: 5px) and (box-shadow: 1px 1px 3px #000) {
div {
border-radius: 5px;
box-shadow: 1px 1px 3px #000;
}
}
This is one you may not see yourself using as much as the others, but it could be useful for testing support for multiple properties.
Final Thoughts
In my opinion @supports is a great addition to the CSS spec.
Given the importance of browser support when creating CSS rules, supported feature detection is a vital part of the process. Using CSS to do this detection instead of having to rely on Javascript speeds up performance, and makes things that little bit more elegant.
The only problem is, ironically, the lack of support for it. However, since CSS degrades well, if a browser does not support @supports it will simply ignore it and read whatever is outside the brackets.
In the light of it’s usefulness, I’m sure we will start to see this rule used more and more.
Do you use @supports in your CSS? How do you currently perform feature detection? Let us know in the comments.