CSS @supports
Feature detection via JavaScript is a client side best practice and for all the right reasons, but unfortunately that same functionality hasn't been available within CSS. What we end up doing is repeating the same properties multiple times with each browser prefix. Yuck. Another thing we do check for CSS property support with JavaScript which leads to brief flashes of content, hopeful code and support, and other problems. Firefox, Chrome, and Opera have just recently added support for CSS @supports
(CSS) and CSS.supports
(JavaScript) to detect browser support for a given style directive. Let's see how it works!
CSS @supports
CSS @supports
directives go in your CSS code just as @media
queries do:
@supports(prop:value) { /* more styles */ }
CSS @supports
allows developers to check style support in a number of different ways.
Basic Property Checks
You can perform basic property and value checks:
@supports (display: flex) { div { display: flex; } }
This is the most basic usage of @supports
.
not
Keyword
@supports
can be paired with a 'not' keyword to check for no support:
@supports not (display: flex) { div { float: left; } /* alternative styles */ }
Multiple Checks and Conditionals
Multiple CSS property checks can be made via 'or' and 'and' chaining:
/* or */ @supports (display: -webkit-flex) or (display: -moz-flex) or (display: flex) { /* use styles here */ } /* and */ @supports (display: flex) and (-webkit-appearance: caret) { /* something crazy here */ }
You can chain multiple multiple conditionals with parens, just as you can in most other programming languages:
/* and and or */ @supports ((display: -webkit-flex) or (display: -moz-flex) or (display: flex)) and (-webkit-appearance: caret) { /* use styles here */ }
The @supports
structure's conditional pattern matches that of @media
's conditional pattern.
JavaScript CSS.supports
The JavaScript counterpart to CSS @supports
is window.CSS.supports
. The CSS.supports
spec provides two methods of usage. The first method of usage includes providing two arguments: one for the property and another for the value:
var supportsFlex = CSS.supports("display", "flex");
The second usage method includes simply providing the entire string to be parsed:
var supportsFlexAndAppearance = CSS.supports("(display: flex) and (-webkit-appearance: caret)");
Great that you can check CSS support via either method -- it avoids property checking on transient nodes and string-building to check for support.
Before using the JavaScript method of supports, it's important to detect the feature first. Opera uses a different method name so that throws things for a bit:
var supportsCSS = !!((window.CSS && window.CSS.supports) || window.supportsCSS || false);
@supports
Usage
In most cases, the best usage of @supports
is setting an older set of styles as backup and then canceling those styles out and enhancing if a given property is supported. One brilliant use case for @supports
is layout. Some edge browsers are now providing support for flexbox while others lag behind. In this case, you could code:
section { float: left; } @supports (display: -webkit-flex) or (display: -moz-flex) or (display: flex) { section { display: -webkit-flex; display: -moz-flex; display: flex; float: none; } }
Other good uses cases will pop up as developers have more time to experiment with the new @supports
feature.
Enabling @supports
If you want to dabble with new features like @support
, you should invest some time installing edge browsers like Canary, Firefox Nightly, and Opera Next. Opera 12.1, WebKit Nightly, and Firefox Nightly all support @supports
. Old versions of Firefox provide support after [layout.CSS.supports-rule.enabled
] is enabled.
@supports
is a welcomed addition to the CSS and JavaScript specs. Feature detection is our number one best practice for feature support and @supports
provides a lower level layer than the hacks we've been using the past few years. I suspect we'll see loads of @support
directives over the next few years as flexbox becomes more useful and widely used!
very nice job. thank you for this great article! I’m looking forward to learn this feature too!
That’s great news!
Too bad that the browsers that support
@support
(hehe) are the ones that support the most of CSS!Well, for now. Can be useful in future, hoping that IE11 will add this feature.
Nice standards.. lol.. with Opera doing it differently again (though who is using it anyway today?) I thought now that they’re adopting webkit, that they would use the same standards as others?
Anyway- this is a nice addition and better than hacks yes, now all we need is IE to update and then every browser should push a silent update.
Ughh, I wish this would end the need for browser prefixes but it looks like you still have to test for them.
Do you have any clue or thought as to why the comma syntax isn’t supported for the
or
in@supports
rules?Browsers seem to only support
or
to match any of the options around them in@supports
but the “normal” media queries only support the,
syntax and not theor
.I made a quick demo here: http://jsbin.com/ihivow/2/
It seems a bit counter intuitive to introduce another database like selecting syntax when CSS already has the
,
syntax in media queries.The
,
syntax feels more CSSy to me.I’ve been using CSSFix: https://github.com/imsky/cssFx
It helps me avoid a lot of the ugly browser prefixes code. Thus far, I haven’t run into any issues (knock on wood).
It’s funny cause right now if you wanna use it I think of:
1- test for its support using Modernizr
2- if it’s supported you use it to check for support of certain CSS features and place it in CSS
3- if not supported fall back to Modernizr to add classes to the body
4- write more CSS to work with older browsers
I feel like “Yo dawg” … any ideas :D ???
I’d like to extend Ahmad’s question and ask: What does the spec say should happen when a back level browser hits one of these rules? Should the contained rules be applied or ignored? Perhaps a question for PPK, but regardless of what the spec says to do, what do browsers actually do?
They will ignore it … The syntax is somehow similar media queries block so it will be ignored.
This
@supports
feature is a new information for me. Thank you for sharing this info.In your last example you test for prefixed versions of display: flex. But in the code you only use the non-prefixed property. What is the use of the prefixed tests?
Good point Rolf — updated the post!
Before it was not enabled in Chrome, but it is now:
https://codereview.chromium.org/13646013
Hooray!
This tool is great (thank you!), but ugly prefixes still breaks a dream about clean code in CSS.
It is about of performance and practicability. Many programmers have to face the sad fact of dealing with already built sites which contain jQuery as main javascript engine. The best way to attack performance issues on those animations that are already built on jQuery (and considering the client won’t support old browsers anymore) is to switch to CSS transitions instead of loading another javascript helper.
It might be fun to see how javascript developers can’t stand the fact that CSS3 appears as a solution for those who are not javascript developers to build animations.
http://troleandogeeks.com/post/98673577700/cuando-el-backend-presume-su-animacion-javascript?ln=en
This looks amazing.
Are there any usercases where Browsers support
@support
but don’t support something like flex?It seems to me that the
@support not
will never pass as@support
is an edge featureSome comment and history on the ‘Opera doing it differently’ comment.
Opera was the first browser to implement this. I reviewed all the tests and functionality for Florian Rivoal who was active in the CSS working group and who had also implemented this.
In the review I said I was sad that they put a new single function on the global object, and suggested the spec could create a CSS object to contain any future functions. So CSS.supports(), Florian thought it a good idea and took it to the CSS WG. But we (as in Opera) shipped the working code already since it had not been agreed to change the spec at that time.
Often why any browser does it differently is because they’re first to implement and this can result in a newer sometimes better API. :)