Same Markup: Using , , and

September 4th, 2010

On this blog we’ve repeatedly discussed enabling the “Same Markup” for Internet Explorer 9. Part of making “Same Markup” a reality involves supporting the right features in IE9 to make the same HTML, JavaScript, and CSS “just work” the same way they do in other browsers. Part of how IE9 contributes to enabling the “Same Markup” is through support for the <canvas>, <audio>, and <video> elements from HTML5. These were introduced in the third platform preview and continue to be improved with each update.

In my first post on “Same Markup”, I described the effort as an “n-way street”. Each browser has a part to play by supporting the right features with the right behavior. Web developers also have a part to play in how they code for cross-browser differences where they unfortunately still exist. The most important part of working across browsers for web developers is to detect features, not browsers. So in this post I’ll outline how to use feature detection for <canvas>, <audio>, and <video>.

Detecting Support from HTML Markup

Unlike other features, support for <canvas>, <audio>, and <video> can be detected directly from HTML markup. This involves simply using the desired element, then placing fallback content inside of it intended for browsers that don’t have support for these elements. Browsers with support will hide this content from the user and display only the <canvas>, <audio>, or <video> element itself.

<!-- Example 1: Basic <canvas> fallback -->
<canvas> This text only displays in browsers without canvas support.
<!-- Example 2: Basic <audio> fallback -->
<audio> This text only displays in browsers without audio support.
<!-- Example 3: Basic <video> fallback -->
<video> This text only displays in browsers without video support.

One caveat to keep in mind is that fallback content is only hidden visually. <script> blocks and other items in fallback content will always execute, even in browsers that support these elements.

<!-- Example 4: <script> always executes in fallback content -->
<canvas> <script> alert("This always runs, even when canvas is supported."); </script>

Of course, fallback content should also be useful. Exactly what qualifies as useful can vary depending on what you are trying to do. One approach is to point the user at a download for an upgrade, but in most cases it is a better experience for consumers to fall back to alternative approaches for delivering the content. For example, if you’re drawing something that doesn’t change much to a canvas, you may be able to fall back to an image that gets generated server-side. A better alternative could involve including a framework which implements canvas on top of existing web technologies or using a widely deployed plug-in.

The <audio> and <video> elements tend to have more options for fallback via plug-ins, whether through a media player or an app built on top of a widely deployed technology such as Flash or Silverlight. At the very least you can provide the user with a link to download the file so they can play it locally. The examples below provide a rough view of this type of fallback, though the <object> tag generally requires a number of varying parameters specific to the chosen plug-in.

<!-- Example 5: Provide useful fallback content for <audio> -->
<audio src="myaudio"> <object type="audio-plugin-mime-type" data="myaudio"> <a href="myaudio">Download the audio file</a> </object>
<!-- Example 6: Provide useful fallback content for <video> -->
<video src="myvideo"> <object type="video-plugin-mime-type" data="myvideo"> <a href="myvideo">Download the video file</a> </object>

Detecting Support from Script

In addition to HTML markup, support for <canvas>, <audio>, and <video> can also be detected from script. This detection can be performed many ways, but one of the simplest is to check for the existence of the appropriate interface object off of window.

// Example 7: Simple feature detection for <canvas>
if(window.HTMLCanvasElement) { // Code requiring canvas support
// Example 8: Simple feature detection for <audio>
if(window.HTMLAudioElement) { // Code requiring audio support
// Example 9: Simple feature detection for <video>
if(window.HTMLVideoElement) { // Code requiring video support

An alternative approach for detecting <audio> and <video> involves checking for the existence of the canPlayType method on a dynamically created <audio> or <video> element. This is used by a number of frameworks and is generally preferred if you also intend to use the canPlayType method to test for supported codecs (which will be covered in a future post). If you simply need to test whether <audio> or <video> is supported, then I find the approach outlined above in examples 8 and 9 to be more obvious and equally as effective.

// Example 10: Alternate feature detection for <audio>
if(document.createElement("audio").canPlayType) { // Code requiring audio support
// Example 11: Alternate feature detection for <video>
if(document.createElement("video").canPlayType) { // Code requiring video support

A similar alternative approach can be used for detecting <canvas> support. In this case, most frameworks have settled on checking for the existence of the getContext method. This makes sense for <canvas> given that this method is required in order to retrieve a context for rendering.

// Example 12: Alternate feature detection for <canvas>
if(document.createElement("canvas").getContext) { // Code requiring canvas support

Next Steps

If you have previously used browser detection to decide whether to use <canvas>, <audio>, or <video>, now is the time to update to use feature detection instead. Also, make sure you have a DOCTYPE at the top of your page (e.g. <!DOCTYPE html>) so your content doesn’t render in Quirks Mode. In IE9, Quirks Mode is used for compatibility and consequently the <canvas>, <audio>, and <video> elements will not work there.

Stay tuned for future posts covering how to detect supported codecs and specify multiple sources using the <audio> and <video> elements.

Tony Ross
Program Manager

Edit 9/3 – added link to earlier blog post in second paragraph