Capability Testing

The web is generally designed to route around damage, to fail quietly. From failed TCP/IP packet delivery to invalid HTML to invalid CSS, we rarely notice what doesn't work. Servers and browsers work it out and give us the best results they can come up with given broken input. The major exception to this is JavaScript. When JavaScript fails, it fails big. Browsers don't continue on running the parts of the JavaScript that still work, like they do with almost every other web standard.

With HTML5 and CSS3, the web is changing fast and JavaScript (or more technically, ECMAScript) is becoming a much larger factor in the way the web works. Anyone who, like me, regularly uses a browser without JavaScript increasingly finds sites that don't work at all without JavaScript. Requiring JavaScript is a risky decision even if everything works, but it also changes JavaScript failures from minor annoyances to disasters.

Meanwhile, all of the new JavaScript functionality has introduced much more opportunity for failure. While new features like <video> or <canvas> work great in modern browsers, older browsers don't understand the new elements, much less the associated JavaScript interfaces. The <video> tag will fail quietly just like any other HTML tag, but when you use JavaScript to tell IE6 to play that video, it will have no idea what you're talking about. And it won't keep listening hoping your JavaScript will stop talking nonsense; it will simply ignore all JavaScript, completely killing your entire shiny new JavaScript-dependent site.

So what do we do about this? First, listen and nod while progressive enhancement advocates say "I told you so." Thanks, that felt good. Now, let's look at some solutions. The first solution you might turn to is browser sniffing. Don't. The idea of sending different JavaScript to different browsers might seem like a good way to solve the problem of different browsers understanding JavaScript differently, but it's not really. Beyond heading down the road toward "this site is best viewed in browser X," the problem with browser sniffing is new browsers are being introduced all the time, and it's impossible to predict what capabilities they might have.

The correct solution to the problem of unknown capabilities is to test for capabilities before using them. For example, almost every tutorial on using the new <canvas> tag starts out with something like this:

<pre>var canvas = document.getElementById('mycanvas'); 
var context = canvas.getContext('2d'); </pre>

But browsers that don't support canvas will die on that second line, because the getContext function doesn't exist in those browsers. The solution to this is very simple: check if the function exists before calling it:

<pre>if (canvas.getContext) {
  var context = canvas.getContext('2d'); 
}</pre>

Capability testing was a good strategy before HTML5, and it's an even better strategy today. Not only is capability testing more important today, but it's also easier. The handy Modernizr JavaScript library wraps up a whole bunch of capability testing in easy to access variables, and also exposes JavaScript capabilities to CSS by adding relevant class names. So if you want to know if canvas will work in the current browser, Modernizr makes this as simple as:

<pre>if (Modernizr.canvas) {</pre>

Capability testing isn't only for new HTML5 awesomeness; it should be used anywhere there's any uncertainty about whether browsers can do something. It can even be used to test the capability of JavaScript itself. For example, if you have a link the runs JavaScript, something like <a href="#" onclick="...">, rather than putting that link in your HTML, add it with JavaScript. With this approach, browsers that aren't capable of running the JavaScript will never see a broken link.

Capability testing is a simple, effective solution to the increasingly common problem of unknown JavaScript support in browsers. And while it’s becoming more important, it’s also becoming easier to do.

Code User Experience

Read This Next