1. Web Design
  2. HTML/CSS
  3. JavaScript for Designers

CSS Feature Detection: Modernizr or Feature Queries?

Scroll to top

In this tutorial, I’ll go over two approaches for detecting whether a browser supports certain CSS features or not. The first one takes advantage of Modernizr, a popular JavaScript library and the second one feature queries, a promising CSS solution.

So, let’s start!

Detecting Features Using Modernizr

As mentioned above, Modernizr is a lightweight JavaScript library which detects HTML5 and CSS3 features in your browser. As long as your page loads, it runs behind the scenes and performs feature tests. Then, it stores the results as properties of a JavaScript object and as classes of the html element. More on that later.

To install and use Modernizr, you can visit its site and download the preferred version.

Note: at the time of writing, Modernizr’s current release is 2.8.3, though version 3 is almost ready. In fact, the team behind the library expects to launch it in the upcoming weeks. A brief overview of this new release can be found here. Furthermore, you can grab the beta version of it by visiting this link.

Once downloaded, place the JavaScript file in your project and include it in the <head> of your html page. Last but not least, in order to enable Modernizr’s functionality you should add the no-js class to the html element.

In the next two sections, I’ll cover the fundamentals of Modernizr. For more advanced concepts make sure to read the documentation

CSS Detection

As discussed above, Modernizr adds a number of classes to the html element. The class names depend on the browser support. If the browser doesn’t recognize some of the feature tests, Modernizr adds the no- prefix before its built-in class names. For instance, supposing we’re testing for the reflection effects, the html element on Chrome 40 looks like this:

While on Firefox 35:

Notice also the js class. When Modernizr runs, assuming JavaScript is enabled in our browser, it replaces the old no-js class with the new one. 

Based on the results received from Modernizr’s tests, we can customize our stylesheets.

Examples

To start, here’s the basic HTML code we’ll use for the rest of the tutorial:

1
<h2 id="reflection">CSS Reflections</h2>

Using the classes given to us by Modernizr we modify the styles of the h2 element as follows:

1
h2 {
2
  color: #c0ccdb;
3
  font-size: 3em;
4
}
5
  
6
.cssreflections h2 {
7
    -webkit-box-reflect: below -.45em -webkit-gradient(linear, left top, left bottom,  from(transparent), color-stop(0%, transparent), to(rgba(255, 255, 255, 0.75)));
8
}
9
  
10
.no-cssreflections h2 {
11
    text-shadow: 0 1px 0 #136ed1,
12
      0 2px 0 #126ac9,
13
      0 3px 0 #1160b6,
14
      0 4px 0 #105cad,
15
      0 5px 0 #0f56a2,
16
      0 6px 1px rgba(0,0,0,.1),
17
      0 0 5px rgba(0,0,0,.1),
18
      0 1px 3px rgba(0,0,0,.3),
19
      0 3px 5px rgba(0,0,0,.2),
20
      0 5px 10px rgba(0,0,0,.25),
21
      0 10px 10px rgba(0,0,0,.2),
22
      0 20px 20px rgba(0,0,0,.15);
23
}

Webkit-based browsers that support reflections will display the h2 element as follows:

While the rest of them (at least those that support the text-shadow property) will apply a different effect, based on a 3D text effect by Mark Otto:

Here’s the example on Codepen:

JavaScript Detection

The second way to check the results derived by Modernizr’s tests is through JavaScript. As already mentioned, Modernizr creates an object with the property names of features which are configured to test. Most of the times, their values return either true or false.

The screenshot below shows how Firefox 35 displays the Modernizr object (Console tab):

As we can see the Modernzir.cssreflections property returns a false value. That happens because Chrome, Safari, and Opera are the only browsers, which support reflections (at the time of writing).

Here’s how we might reproduce the previous example with JavaScript, by adding the reflection and no-reflection classes to our <h2 id="reflection"> manually:

1
var element = document.getElementById('reflection');
2
if (Modernizr.cssreflections) {
3
    element.className = 'reflection';
4
} else {
5
    element.className = 'no-reflection';
6
}

Then styling with the relevant CSS:

1
.reflection {
2
    /* apply reflection property */
3
}
4
5
.no-reflection {
6
    /* apply text-shadow property */
7
} 
8

And the new demo on Codepen:

Detecting Features Using Feature Queries

Without doubt, Modernizr is a valuable tool in every frontend developer’s arsenal. But wouldn’t it be better if we could replicate Modernizr’s tests with pure CSS? Thankfully, we can do that by using feature queries. These are conditional rules which allow us to apply different styles depending on browser support. They work just like media queries. And yes, besides the CSS edition they’re also coming to JavaScript.

Ready to have a look?

CSS Detection

To define feature queries in our CSS we have to use the @supports and @supports not rules. Their syntax looks like this:

1
@supports(test condition) {
2
    /* apply rules */
3
}
4
5
@supports not(test condition) {
6
    /* apply rules */
7
}

The condition includes property: value pairs of features we want to test. Browsers that support the features apply the target rules, which we specify within the @supports rule. Otherwise, the styles within the @supports not rule are executed.

Using the AND and/or OR logical operators we can create complex tests. However, keep in mind that these operators should be separated by parenthesis.

Let’s see two examples. As we already know, our HTML is dead simple! It’s just an h2 element.

In this first example, we use the background-color property to specify the background-color of the body element. To make things more interesting, we also create a CSS variable. Browser support is divided into the following categories:

  1. Browsers that support feature queries and CSS variables (currently only Firefox 31+).
  2. Browsers that support feature queries, but don’t support the CSS variables.
  3. Browsers that don’t support feature queries nor CSS variables.

Depending on these circumstances, the body element will show a different background-color.

Here’s the CSS code based on the assumptions above:

1
body {
2
  --bg-color: #98FB98;
3
  background-color: khaki;
4
}
5
6
@supports (background-color: var(--bg-color)) {
7
  body {
8
    background-color: var(--bg-color);
9
  }
10
}
11
12
@supports not(background-color: var(--bg-color)) {
13
  body {
14
    background-color: tomato;
15
  }
16
}

For instance on Safari, which belongs to the third category our element would look like this:

Then Chrome, which can interpret the Feature Query, but doesn’t support CSS variables, belongs to the second category:

Lastly Firefox, which sits in the first category:

And the embedded example on Codepen:

Another Example

In this case we’ll expand the test condition to contain a second rule. More specifically, now we’re targeting browsers that support not only reflections but also text-stroke effects.

Here’s the code for that behavior:

1
    @supports ((/* reflections condition */) and (-webkit-text-stroke: 1px tomato)) {
2
3
        h2 {
4
            /* apply reflection property */
5
            -webkit-text-stroke: 1px tomato;
6
        }
7
    }
8
9
    @supports not ((/* reflections condition */) and (/*stroke condition*/)) 
10
    {
11
        h2 {
12
            /* apply text-shadow property */
13
        }
14
    }

For instance, browsers (at the time of this writing only Chrome 28+) which support feature queries, reflections, and text-stroke effects will display the h2 element as follows:

Below is the embedded example on Codepen:

JavaScript Detection

Feature queries can also be defined through JavaScript. To do so, we have to use the CSS.supports method. Here are its possible parameters:

1
CSS.supports(propertyName, propertyValue)
2
3
CSS.supports(test condition)

The result of this method is a Boolean value indicating whether the browser supports the feature(s) or not. Finally, we should wrap the parameters in single or double quotes.

Using the JavaScript edition of feature queries our last example can be reproduced as follows:

1
var result = CSS.supports('(/*reflections condition*/) and (/*stroke condition*/)');
2
3
var element = document.getElementById('reflection');
4
if(result) {
5
  element.className = 'reflection';
6
} else {
7
  element.className = 'no-reflection';
8
}

The corresponding demo:

Browser Support

In general terms, the browser support of feature queries is good. At the time of writing Firefox (22+), Chrome (28+), and Opera (12.1+) all support this CSS functionality. Hopefully, upcoming versions of IE will understand the condition rules (they’re working on it!) as well.


Polyfills

If you want to use feature queries in your projects, but you’re a bit skeptical regarding the browsers that understand them, you’ll find some useful polyfills below:

Conclusion

In this tutorial, I went through two useful methods you can use to deliver reliable cross-browser experiences. Taking advantage of Modernizr and/or feature queries will help you understand the benefits of designing for features and not for browsers. Modernizr is the current stable solution, but feature queries are coming, so the choice is yours!

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.