Blog post cover
Arek Nawo
07 Jul 2021
5 min read

CSS feature detection in JavaScript?!

TL;DR; Use @media-like @supports rule for feature detection in CSS, its equivalent - CSS.supports() in JS, and library like Modernizr when those feature detections aren’t supported (e.g. IE).

When you need to use newer JS features in older browsers, you can either use a preprocessor or polyfills. In most use cases, they’re able to do the job with acceptable performance and/or bundle size costs.

However, with CSS, things aren’t that simple. You can use a preprocessor like SCSS to add additional functionalities and transforming tools like PostCSS to add prefixes and so on, but many CSS features won’t be “polyfillable”.

That’s why it’s important to do proper feature checks and implement fallbacks where necessary. Let’s see how it’s done!

CSS @supports rule

Starting off with the basics, there’s a dedicated CSS at-rule for detecting supported CSS features right from the stylesheet! It’s called CSS Feature Query, aka @supports, and is relatively well-supported, with all popular browsers, except IE supporting it.

@supports can be used at the top level of your CSS file or nested inside another @supports or @media.

As for syntax, it’s similar to @media, with your feature checks having a form of (checked-property: checked-value) wrapped in a parenthesis:

@supports (aspect-ratio: 1 / 1) {
  /* When aspect ratio is supported ( */

Apart from that, you can also use not, and, and or operators, as well as an additional parenthesis to form more complex queries:

@supports (display: grid) and (not (display: inline-grid)) {}

Worth noting is the newer selector() function for checking support for provided selectors, coming with a bit worse support than the rest of the API.

@supports selector(ul > li) {
  /* Child combinator selector supported */


Now, the @supports rule translates well into JS code, thanks to the CSS.supports() method. It’s almost as well supported as the @supports, but with slightly different syntax.

const isSupported = CSS.supports("aspect-ratio", "1 / 1");

if (isSupported) {
  // Aspect ratio supported

The method accepts the checked property name and then its value as arguments, returning a boolean. Instead of CSS operators like and, or, and not, you can use their logical JS equivalents - &&, ||, and ! respectively.

With that said, in newer browsers, CSS.supports() can also be used with more advanced CSS syntax - including the operators and selector() function. With that, it’s also possible to use the method as a template string tag!

const isSupported = CSS.supports("(display: grid) or (display: flex)");
// or
const inSupported = CSS.supports`(display: grid) or (display: flex)`;

When support checks aren’t supported

So, all seems good, but there’s one problem - what to do when support checks aren’t supported? Both @supports and CSS.supports() are great, but they only work on relatively recent browsers, meaning no IE support - which is typically the main focal point of feature checks.

Thus, if you want to support IE, the first thing - why? - and second, you’ll need some fallbacks even for feature checks themselves.

Available workarounds

There are many ways to approach this problem. You can, for example, write the specific tests yourself, testing whether certain elements react to selected CSS properties, or if they generate any styles. You could also use ready CSS.supports() shims and smaller tools like that.

Arguably, the best approach would be to use a full feature detection library like Modernizr.


Modernizr isn’t a new library, and it’s well-known in the web development ecosystem. Although with modular polyfills and preprocessor like Babel and PostCSS it’s not as popular as it was before, it’s still great when dealing with CSS support checks for older browsers.

Modernizr landing page
Modernizr landing page

Simply download it from NPM or through bundle configurator, and enjoy tens of available JS and CSS tests!


There you go! The best ways to do CSS feature detection - in both CSS, as well as JS. For most cases, basic polyfills and preprocessors will do the job just fine. However, when going extreme with e.g. IE support, you’ll want to take a second look at Modernizr. And if you land somewhere in the middle, amazing @supports and CSS.supports() APIs are here for you!

Thoughts or questions? Leave them in the comment section below! For more web development content, follow me on Twitter, Facebook, or through my newsletter. Thanks for reading and happy coding!

By accessing and placing an order with Creative Tim, you confirm that you are in agreement with and bound by the terms and conditions contained in the Terms Of Use outlined below. These terms apply to the entire website and any email or other type of communication between you and Creative Tim.

Summer arrivals at Creative Tim!

Front-end and back-end stacks with up to 90% OFF on Creative Tim! Choose a React, Bootstrap, Vue, Angular, or Laravel Stack, or go all in with the Summer Full Stack which includes 66 premium products! Hurry up and grab Creative Tim Summer deals!

If you need

Custom Web App

I can help you get your next project, from idea to reality.

© 2024 Arek Nawo Ideas