Writing your own simple feature tests
Progressive enhancement is an approach to web development in which your provide universal access to content to all devices, and layer in additional features and functionality for browsers that support them.
For this approach, you need to run a simple feature test to check what the browser is and isn’t capable of. Modernizr is a great tool for this, but today, I want to show you how you can write your own simple feature tests.
What a feature test looks like
At it’s core, a feature test is a simple if statement:
if ( support for feature exists ) {
// Do something
}
I use feature tests in two ways:
- I'll add classes to the document to activate certain styles in my CSS file.
- I'll wrap them around my JavaScript to ensure the browser can handle the API's used.
Let’s look at some examples.
Checking for modern JavaScript support
I use modern JavaScript API’s in my scripts that don’t work in older and less capable browsers. These API’s include query selectors, event listeners, and foreach loops. Here’s the if statement I use:
if ( 'querySelector' in document && 'addEventListener' in window && Array.prototype.forEach ) {
// Do stuff...
}
Some of my scripts use CSS to hide and show elements. By default, I want all elements visible. They should only be hidden if the browser has the appropriate JavaScript support to make them visible. To do that, I include this script:
if ( 'querySelector' in document && 'addEventListener' in window && Array.prototype.forEach ) {
document.documentElement.className += 'js';
}
That adds a .js class to the <html>
element. In my CSS, I’ll include something like this:
.js .example {
display: none;
visibility: hidden;
}
Now, elements with the .example
class are only hidden when the appropriate API’s are supported.
I also don’t want to run scripts that use unsupported API’s, as that can result in errors and weird layout quirks. I’ll wrap a feature test around my script like this:
if ( 'querySelector' in document && 'addEventListener' in window && Array.prototype.forEach ) {
// My scripts go here...
}
Checking for @font-face
support
I love using icon fonts, but certain browsers (notably Opera Mini and IE 9 on Windows Phone 7) don’t support font embedding. I also use the :before
pseudo selector to include icons in my HTML.
For browsers that don’t support either of those, users will see empty squares where the icons should be. I’d rather they see nothing at all, or in some cases, see text instead. Paul Irish and Diego Perini shared two little functions that check for support of these features.
I include these functions in my JS file, and then use this if statement:
if (isFontFaceSupported && selectorSupported(':before')) {
document.documentElement.className += 'font-face';
}
Then in my stylesheet, I make sure that I prefix my @font-face
styles with .font-face
.
Including a feature test on your site
So you’ve written your feature test. Now where do you put it?
Tests that I wrap around scripts go in my main JavaScript file. Feature tests that add a class to the document go in their own file that I usually name feature-test.js
. While most of my JS files go in the footer for better performance, I want the test to run as quickly as possible to avoid “flashes of unstyled content” (or FOUC, as it’s sometimes called).
I include the feature-test.js
in the <head>
element:
<script src="feature-test.js"></script>
How do you know what to check for?
Google is a great place to start. A lot of the conditional statements can be found on the Mozilla Developer Network, where they’re included as part of the polyfill recommendations. And Paul Irish, who’s a jQuery team member and lead developer at Modernizr, shares a lot of the code they use on GitHub.