Skip to main content

Continuing with unobtrusive Flash insets. Here's how to present Flash video in an accessible manner. Including as required: Alternate media, captioning, audio description, and text transcript. A simple, unobtrusive, and lightweight method.

- (incept: )

Embedding Flash video accessibly

A simple, unobtrusive, and lightweight method to embed Flash video accessibly into your page. Content in the HTML is replaced with a Flash inset only if both JavaScript and the minimum level of Flash are supported. Multiple Flash insets are also catered for. The method depicted here is a furtherance to that employed by Tesco Direct to deliver their TV adverts online.

The best media player out there is undoubtedly Jeroen Wijering's mediaplayer. Feature laden, accessible and skinable. At the time of writing version 4.2. To be honest it needs a tutorial in itself. I cannot recommend this player highly enough. If you're using anything else, change.

There are many advantages to this solution:

  1. The simplest of installation set-ups.
  2. Tests for the users Flash version, and only inserts if supported.
  3. Unobtrusive. No extra mark-up in the (X)HTML.
  4. Accessible with or with out JavaScript.
  5. Semantic W3C formal grammar, validates even after the Flash is embedded.
  6. Accessible, with or with out Flash.
  7. Very small footprint (2.59 KB).
  8. Multiple Flash insets per page.
  9. A cross-browser, cross-platform solution.

Caveat: It appears Firefox 3 has an issue playing video with Adobe's Flash Player v9. The recommended fix is to download Adobe's Flash player 10 beta. Rubbish if you ask me.

From an accessibility perspective there are two types of video:

  1. Essential page content. Which requires: An alternate video version(s), a text transcript, and captioning if you're really serious.
  2. A non-essential embellishment to the page content. Which only requires an image, with good alt text, as an alternative.

Both use the same JavaScript method presented but "essential content" has a little more XHTML.

Embedding Flash video example

Here's the example running on a bare bones demo page. There's a zipped complete set of the files and just the JavaScript used. The zipped set includes agressively minified versions. The smallest of which is only 2.59 KB.

I've still to add an audio description.

How it works

The method is extremely simple. Basically an image in the content is replaced by a video.

Once the page has completely loaded the script looks through all the images on the page and makes a list of those with a class name of img2flv. For each it replaces the content of the image container. The <div> in the example. All the variable parameters required are taken from the image and applied to the video player.

The XHTML

The video parameters are taken from the image in the html:


<div>
  <img class="img2flv" src="example1.jpg" width="320" height="240" title="" alt="Example 1: Belly dance" />
  <div class="altContent">
    <p>Download <a href="example1.mp4">Belly dance video [MP4]</a> or <a href="example1.txt">Belly dance text transcript [TXT]</a>.</p>
  </div>
</div>

When the video is a non-essential embellishment to the page content you can leave out the altContent div but ensure the image alt text is accurate. Otherwise please ensure there is an MP4 and TXT version of the content available.

The JavaScript

JavaScript constants

Some global constants are required:


var minFlash=8;
var img2flvClass="img2flv";
var altContentClass="altContent";
var flvPlayer="player.swf";
var playerSkin="snel.swf";

Where:

  • minFlash=8 - Is the minimum version of the Flash player needed to run the video. I use the On2 VP6 codec for better quality and streaming which requires at least v8. Full screen requires version 9+.
  • img2flvClass="img2flv" - The class name associated to any image which is to be replaced by a FLV video.
  • altContentClass="altContent" - Class of alternate content div to display if Flash or JavaScript is unsupported.
  • flvPlayer="player.swf" - The location and name of the FLV player. Used here is v4.2 of Jeroen Wijering player
  • playerSkin="snel.swf" - The location and name of the player skin. Used here is Snel v1.0 by LongTail Video

Standard functions

A few of my personal standard functions to make life easier:


function $id(i){return(document.getElementById(i)?document.getElementById(i):false)}
function idExists(i){return($id(i)?true:false)}
function domFunctions(){return (document.getElementById&&document.getElementsByTagName)}
function isFlash(v){var t=20,i=0;if(navigator.plugins&&navigator.plugins.length){for(var x=0;x<navigator.plugins.length;x++){if(navigator.plugins[x].name.indexOf('Shockwave Flash')!=-1){i=parseInt(navigator.plugins[x].description.split('Shockwave Flash ')[1]);break}}}else if(window.ActiveXObject){for(var x=2;x<=t;x++){try{if(eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+x+"');"))i=x}catch(e){}}}return((i>=v)?i:0)}

/* author: Simon Willisons - http://simon.incutio.com/archive/2004/05/26/addLoadEvent */
function addLoadEvent(f){var o=window.onload;if(typeof window.onload!='function'){window.onload=f}else{window.onload=function(){o();f()}}}

Where:

  • $id(i) - same as writing document.getElementById(i)
  • idExists(i) - Checks an id exists returning true or false.
  • domFunctions() - Checks DOM functions used are available.
  • isFlash(v) - returns the flash version if it's >= v otherwise 0.
  • addLoadEvent(f) - Allows for multiple window.onload events.

Flash media player object creation

Utilises player.swf v4.2 by Jeroen Wijering.

Requires the image and FLV to have the same name and be in the same location. Pass in the id of the html image. The video properties: width, height, location and name are extracted from it, as is name and location of the captions file if used.


function flashVideo(id){
  var obj=$id(id);
  if (obj.src){
    var image=obj.src;
    // apply image to background of parent container for a smooth changeover to video
    $id(id).parentNode.style.background="url("+image+") no-repeat";

    var f=image.substring(0,image.lastIndexOf("."))
    var video=f+".flv";

    var appWidth=obj.width;
    var appHeight=obj.height;

    // alternative content
    var captions=f+".captions.xml";
    var download=f+".mp4";
    var altText=obj.alt;
    var alt=$id(id).nextSibling.nextSibling;
    var altContent=(alt && alt.className==altContentClass)?alt.innerHTML:"";
    var parent=obj.parentNode;
    if (video && image && parent && appWidth && appHeight && flvPlayer && isFlash(minFlash)){
The Flash variables

      var flvVars='file='+video;
      flvVars+='&amp;displayheight='+appHeight;
      flvVars+='&amp;displaywidth='+appWidth;
      flvVars+='&amp;image='+image;
      flvVars+='&amp;autostart=false';
      flvVars+='&amp;controlbar=over'; // over/bottom/none
      flvVars+='&amp;screencolor=ffffff';
      flvVars+='&amp;skin=snel.swf';

      // accessibility options
      flvVars+='&amp;link='+download;
      flvVars+='&amp;plugins=accessibility-1';
      flvVars+='&amp;captions='+captions;
      flvVars+='&amp;accessibility.fontsize=22';
The Flash object

      var str='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version='+minFlash+',0,0,0" width="'+appWidth+'" height="'+appHeight+'">';
      str+='<param name="movie" value="'+flvPlayer+'" />';
      str+='<param name="flvQuality" value="high" />';
      str+='<param name="allowfullscreen" value="true" />';
      str+='<param name="flashvars" value="'+flvVars+'" />';
      str+='<param name="wmode" value="transparent" />';
      str+='<!--[if !IE]> <-->';
      str+='<object data="'+flvPlayer+'" width="'+appWidth+'" height="'+appHeight+'" type="application/x-shockwave-flash">';
      str+='<param name="flvQuality" value="high" />';
      str+='<param name="allowfullscreen" value="true" />';
      str+='<param name="flashvars" value="'+flvVars+'" />';
      str+='<param name="wmode" value="transparent" />';
      str+='</object>';
      str+='<!-->';
      str+='<p>'+altText+'</p>';
// place here if only required for accessibility
//      str+=altContent;
      str+='<![endif]-->';
      str+='</object>';
// place here if always required (recommended)
      str+=altContent;
Display alternate content if Flash unavailable then insert new content and close

    }else{
      // no flash, offer alternatives if available.
      var str=parent.innerHTML;
    }
    parent.innerHTML=str;
  }
}

Find the image(s) to replace

The image replacement function. It works generically by class name:


/* Parameters:
  The class name for generic replacements.
  The name of the function to build the Flash video object.
*/
function imageTo(classN,func){
  var imgs=document.getElementsByTagName('img');
  var imgIDs=new Array();
  var c=0;
  for (var i=0;i<imgs.length;i++){
    if (imgs[i].className==classN){
      if (!imgs[i].id){
        imgs[i].id=classN+i;
      }
      imgIDs[c++]=imgs[i].id;
    }
  }
  for (var i=0;i<imgIDs.length;i++){
    func(imgIDs[i]);
  }
}

This function scans through all the images and collates those with a specified class name. An id is assigned if not already present. Each id is then passed to a function which replaces the content.

Setting it all up:

If the required Dom functions are supported then run setup on page load.


function setup(){
  imageTo(img2flvClass,flashVideo);
}

/* test dom functions used are supported */
if (domFunctions()){
  addLoadEvent(setup);
}

Hiding the alternate content

Best practice states the alternate formats should always be visible.

Only if you really must hide the alternate versions, unless JavaScript or Flash are unsupported, then do it in this manner.

In the flashVideo function change the commented lines so:


// place here if only required for accessibility
      str+=altContent;
      str+='<![endif]-->';
      str+='</object>';
// place here if always required (recommended)
//    str+=altContent;

Update history

29th November 2008
Upgraded the player to version 4.2 after the release of the accessibility plugin.
Removed the necessity for the image to have an id.
Added a background image to the container to allow for a smooth transition between image and video.
Added alternate content files MP4 and text transcript.
Added closed captioning.
22nd September 2008
Original upload using version 3.12 of the flvplayer.

Further reading