Feature detection with CSS using @supports

Code6 min readView on GitHub

Feature detection is a core part of day to day life as someone who makes websites. It's one of those features I usually hand off to Modernizr. I recently saw a tweet, which spurred the curiosity to see if we’re ready to use the @supports feature query. Now is definitely a good time to start.

The opportunity isn't huge so far, as generally browsers are quite similar in feature sets. Though it's a good practice to get into and I'm hoping to make note to myself and others that CSS feature detection is viable.


The browser support is more optimistic than I thought. The support is very broad. With globally just short of 70% of browsers supporting it, as of writing. You’re best referring to can I use, for up to date statistics.

All major modern desktop browsers support it, and iOS Safari, Android Browser and Chrome for Android support it too. So this is a great reason to start using it.


Usage is very familiar, it’s similar to media queries and all other conditional rules.


The general usage is checking for a property and value. It isn’t currently possible from my testing to just check for a property eg: box-shadow or transform.

@supports (display: flex) {
  … }


Prefixes are rarely used now. However, you can check for the existence of those.

@supports (display: -webkit-flex) {
  … }


The way to check whether something doesn’t exist is a matter of putting not before the condition.

@supports not (display: flex) {
  … }

This but not that

This is one I was thinking the behaviour would be similar to programming languages. It isn’t. However, the approach works nicely as the code example will demonstrate.

At one point, Firefox didn’t support the flex-wrap property. This made flexbox not an option in that browser.

@supports (display: flex) {
  .supports {
    display: flex; }

  @supports not (flex-wrap: wrap) {
    .supports {
      display: block; } } }

Multiple conditions, or and and

Multiple conditions can be checked for, this makes @supports versatile to many needs. This is an alternative approach to the previous example.

@supports (display: flex) and (flex-wrap: wrap) {
  … }

Multiple grouped conditions

If necessary you can make more complex queries. You can group them together with extra brackets.

@supports (columns: 1) or ((display: flex) and (flex-wrap: wrap)) {
  … }

Mixing with media queries

It’s possible, this is more to cover all bases.

@media (min-width: 600px) {
  @supports (mix-blend-mode: overlay) {
    mix-blend-mode: multiply; } }

Pseudo selectors

There is no mention of this in the specification. You can’t currently test for pseudo selectors. I can’t think of any exact use cases where it would be beneficial, because it would be ignored by the browser anyway.

I feel like there could be some benefit to it, due to new level 4 selectors. For what it’s worth, it’s handy to know that this isn’t currently supported.

Ideas for usage

Today the usage isn’t too apparent, there are some good uses that I detail. As time passes they will become much more apparent and reduce the reliance on JavaScript.


When you hyphenate a block of text, you’re afforded the ability to justify text. With hyphenation you’re not left with the possibility of awkward rivers. Not many browsers support this, but it’s a simple and convenient way to allow it without awkwardness being forced upon other browsers.

@supports (-webkit-hyphens: auto) {
  p { 
    -webkit-hyphens: auto;
    text-align: justify; } }

Background blur with backdrop-filter

As of writing this is only supported in iOS Safari 9 and Safari 9. It’s useful for getting the iOS blur going on with fixed headers. I’ve used it on content regions, with a lower opacity and have retained good legibility. For the non-supporting we can increase the opacity.

@supports (backdrop-filter: blur(12px)) {
  .content {
    background-color: rgba(255, 255, 255, .3);
    backdrop-filter: blur(12px); } }

@supports not (backdrop-filter: blur(12px)) {
  .content {
    background-color: rgba(255, 255, 255, .8); } }

Unsupported background-blend-mode properties

CSS blend modes still have fairly low support as of writing. In some cases specific modes aren’t supported. This makes for a good use case for @supports.

In this example you check for support for background-blend-mode: color and apply that in the feature query. This gives us the look we are after. However if we have text over the image it may not be legible. So for our alternate look, you can position a layer over the image.

.image {
  background-image: url(‘my-image.jpg’); }

@supports (background-blend-mode: color) {
  .image {
    background-color: green;
    background-blend-mode: color; } }

@supports not (background-blend-mode: color) {
  .image {
    position: relative; }

  .image:before {
    content: “”;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: red;
    opacity: .8; } }

Exclude IE 11 from flexbox

As no version of IE supports @supports and from my experience the most buggy implementation of flexbox is in IE 11. We give ourselves peace of mind. It should go without saying, but you rule out other older browsers with this approach too.

@supports (display: flex) and (flex-wrap: wrap) {
  … }

Final thoughts

I found this to be a valuable topic to explore. @supports looks like a great addition for feature detection. It’s going to become a big part of our CSS. While there isn’t too many use cases right now, this will grow and grow over the coming months. With grid layout, shapes and scroll snap points to name a few, there is more opportunity than what I have mentioned.

I’m a tea drinker, but it’s equally appreciated if you found the article useful.

Get the articles

It’s my aim to help you be a better designer. Join my monthlyish email list and I’ll send new tutorials to help you design & code beautiful websites. You can unsubscribe anytime.