This screencast is a part of our AtoZ CSS Series. You can find other entries to the series here.
Transcript
When using new or experimental CSS, it can be useful to know if the browser supports the features we’re writing code for.
Feature detection is often done in JavaScript with tools like Modernizr but in some browsers, we can now detect capabilities from CSS.
The @supports
rule allows us to conditionally apply styles for features that are or are not supported.
In this episode we’ll learn all about
- Browser support for various CSS features
- How the
@supports
at-rule works - and how to provide alternative styles for unsupported features
Browser Support
If you’ve been writing CSS for any length of time, you’ve probably discovered that not all browsers render things the same way and don’t all support the same features.
A fantastic resource that I use almost daily for checking browser support is the website caniuse.com.
This site allows you to search a database of support tables to find out which versions of which browsers support which features.
In the previous episode, we learned about the :required
pseudo class, which is supported in IE10, Firefox, Chrome, Safari, Opera and Blackberry but not Opera Mini or iOS Safari or Android Browser.
We also learned about @keyframes
in “Episode 11: @keyframes
“. which are supported in all current browsers apart from Opera Mini but is only available in IE from version 10 and is prefixed in Chrome, Safari, Opera, Android and Blackberry.
As you can see, the feature support landscape is vast and complex. This resource is amazing and an integral part of knowing what will work under what browsing conditions. It allows us to decide what features we may need to provide fallbacks for in case the required feature is key to the design or functionality of the site.
The @supports
rule
@supports
is an at-rule, a bit like the @media
queries which we looked at in “Episode 13: Media Queries“.
These at-rules apply styles contained within them, only if a condition is true.
The condition is contained within parentheses and contains a CSS property followed by a value, separated by a colon.
@supports (property: value) {
/* styles applied if the condition is true */
}
If the CSS property inside the brackets accepts a value with the specified syntax, the condition is true.
If we wanted to detect support for unprefixed CSS animations, we could use the following snippet:
@supports (animation-name: test) {
body {background: #cc3f85;}
}
Here I’m using a visual cue of making the background
of the page pink to show whether the feature is supported or not. We can see that the background
is still black, so unprefixed animations are not supported in Chrome, which is what I’m currently using here.
@supports (animation-name: test) or (-webkit-animation-name: test) {
body {background: #cc3f85;}
}
We can use the keyword or
to check multiple properties or multiple vendor prefixes. In this case, the background
does change color, which tells me that Chrome supports the webkit
prefixed version of the animation
property.
It’s also possible to specify multiple conditions with and
or to negated a condition with the not
keyword.
Providing fallback styles
We can use these support conditions to check for features but we can also use them to provide fallback styles in the case where a feature isn’t supported.
I’ve got an image here with a caption positioned over the top of it. The caption has a semi-transparent background using hsla
which we covered way back in “Episode 3: CSS color
Syntax“.
hsla
isn’t supported in old versions of IE so users of that browser will see no background
at all. Due to the nature of this image and the color of the text, the caption is barely legible which is a real usability problem.
We could create the default style with a solid background
color that fits the design and then use @supports
to add the semi-transparent background
if the feature is available.
.caption {
background: #000;
}
@supports (background: hsla(0, 0%, 0%, 0.5) {
.caption {
background: hsla(0,0%,0%,0.5);
}
}
You could argue that this is a little long winded and a much more common approach to this particular problem would be to just allow the hsla
declaration to override the solid background as follows:
.caption {
background: #000;
background: hsla(0,0%,0%,0.5);
}
This simple approach works fine in this case, but if we wanted to add a lot of CSS if a certain feature was or wasn’t supported, we’d need something more comprehensive.
A good example would be something like flexbox which is a completely different layout model for creating complex user interfaces.
We could start with a float or position based layout as a good solid base, but then detect flexbox with @supports
and take advantage of all the features that new layout engine provides.
Here I’ve made an app-like header bar which shows the name of the view with back and forward buttons to the left and right. To get this effect, we can use a combination of absolute positioning and text-align center.
However, with flexbox support, we can just set the nav container to display:flex
and justify-content
with space-between
to equally space the three elements out.
We could wrap the flexbox styles in an @supports
rule and wrap the fallback styles with one for not (display:flex)
.
nav {
background: #eee;
padding: 10px;
}
@supports not (display:flex) {
nav {
text-align: center;
}
.nav-back {
position: absolute;
left: 1em;
}
.nav-forward {
position: absolute;
right: 1em;
}
}
@supports (display:flex) {
nav {
display: flex;
justify-content: space-between;
}
.nav-back,
.nav-forward {
position: static;
}
}
It’s worth noting that browsers that don’t support flexbox, almost certainly don’t support @supports
so to make this backwards compatible, the @supports not (display:flex)
condition would have to be removed.
While I’m really looking forward to this feature gaining more traction, it’s still a long way off being useful as the browser support for @supports
itself is quite limited.
In the meantime, I tend to use the Modernizr JavaScript library for feature detection instead.
This will add classes to the html
element like flexbox
if the feature is supported or no-flexbox
if it’s not. These can then be used in place of the @supports
rule:
nav {
background: #eee;
padding: 10px;
}
.no-flexbox {
nav {
text-align: center;
}
.nav-back {
position: absolute;
left: 1em;
}
.nav-forward {
position: absolute;
right: 1em;
}
}
.flexbox {
nav {
display: flex;
justify-content: space-between;
}
.nav-back,
.nav-forward {
position: static;
}
}
Feature detection and cross-browser support are an important but often frustrating part of front-end design and development. But with the tools we’ve looked at here, hopefully, some of that pain can be eased and we can continue to focus on just making awesome websites.
![Guy Routledge](https://uploads.sitepoint.com/wp-content/uploads/2016/01/1452039161Guy-Routledge-96x96.jpg)
Front-end dev and teacher at The General Assembly London. A to Z CSS Screencaster, Founder of sapling.digital and Co-founder of The Food Rush.