Skip to main content

Add Flash insets to your website in an unobtrusive and accessible manner.

- (incept: )

Embedding Flash accessibly

A simple, unobtrusive, and lightweight method to embed a non-interactive Flash piece 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 currently in use on Tesco Direct.

Example

example image

Here's the same 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 minified versions. The smallest of which is only 1.71 KB.

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 (1.71 KB).
  8. Multiple Flash insets per page.
  9. A cross-browser, cross-platform solution.
  10. May be inside a link.

Caveat: It will not make a Flash piece accessible in itself.

How to implement

All that is required is a link to the script and a contained image in the html:


<script>img2swf.js</script>

<div>
  <img class="img2swf" src="example.jpg" width-"160" height="160" title="" alt="alt text here" />
</div>

Ensure the image has a class name of "img2swf".

The image and swf must be in the same location. They must also share the same name (with different extensions) and dimensions.

Place the script last in the <head> or last inside the<body> sections.

How it works

Once the page has loaded the script looks through all the images on the page and makes a list of those with a class name of img2swf.

For each one it then fetches the swf file and replaces the content of the image container. The <div> in the example.

Coding specifics

In the (X)HTML

Place a holding image which displays when Flash or JavaScript is unavailable. The image must have a class of img2swf:


<div>
  <img class="img2swf" src="example.jpg" width-"160" height="160" title="" alt="alt text here" />
</div>

Multiple images for replacement are allowed just ensure they share the class name.

The JavaScript

Instantiate the closure and set global variables:


var img2swf=function(){
  var minFlash=7;
  var imgClass="img2swf";

MinFlash is the minimum version of Flash needed to run.

Use an onload mechanism to ensure the page has loaded before trying to replace the images. I use Simon Willisons onload handler:


  /* author: Simon Willisons - http://simonwillison.net/2004/May/26/addLoadEvent/ */
  function addLoadEvent(f){var o=window.onload;if(typeof window.onload!='function'){window.onload=f;}else{window.onload=function(){if(o){o();}f();};}}

A neat little function to find the Flash version supported on the browser. This originally was part of a much larger script which has been stripped down to the bare essentials. I've lost the reference for the original, if anyone has a clue please contact me. The function does not detect Flash on all systems but if it can't detect it leaves the accessible alternative. Saying that I've not known it ever fail.


  function isFlash(v){
    var testTo=20, installed=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){
          installed=parseInt(navigator.plugins[x].description.split('Shockwave Flash ')[1]);
          break;
    } } }
    else if (window.ActiveXObject){
      for (var x=2;x<=testTo;x++){
        try {if (eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash."+x+"');"))installed=x}
        catch(e){}
    } }
    return((installed>=v)?installed:0)
  }

The work horse:


  function flashInset(id){
    if (isFlash(minFlash) && document.getElementById(id)){
      var obj=document.getElementById(id);
      if (obj.src){

        // Replace the image src extension with swf
        var src=obj.src.substring(0,obj.src.lastIndexOf("."))+".swf",

            // Get the image properties
            width=obj.width,
            height=obj.height,
            altText=obj.alt,
            parent=obj.parentNode;

        // If img in a link then go up a parent level
        if (parent.href){parent=parent.parentNode;}

The build for the inset code uses Ian Hicksons object method which is simple, effective and does away with the <embed> tag.


        // Check required properties are available
        if (src && parent && width && height){

          /* Build the Flash object */
          var str='<!--[if !IE]> -->';
          str+='<object data="'+src+'" width="'+width+'" height="'+height+'" type="application/x-shockwave-flash">';
          str+='<!-- <![endif]-->';
          str+='<!--[if IE]>';
          str+='<object id="'+id+'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version='+minFlash+',0,0,0" width="'+width+'" height="'+height+'">';
          str+='<param name="movie" value="'+src+'" />';
          str+='<!--><!-- -->';
          if (!(typeof flashVars==="undefined")){
            str+='<param name="flashvars" value="'+flashVars+'" />';
          }
          str+='<param name="quality" value="high" />';
          str+='<param name="wmode" value="transparent" />';
          str+='<p>'+altText+'</p>';
          str+='</object>';
          str+='<!-- <![endif]-->';

          /* set container dimesions to minimise layout disturbance */
          parent.style.width=width+"px";
          parent.style.height=height+"px";
          parent.style.overflow="hidden";

          /* Replace the images parent with the built object */
          parent.innerHTML=str;
        }
      }
    }
  }

Okay so I used innerHTML. It's smaller, faster and fully supported by all browsers.

Set up. Find each image with the class img2swf and add it to an array. Then use the array to call the flashInset function.


  function init(){
    addLoadEvent(function(){
      var imgs=document.getElementsByTagName('img'),
          imgIDs=[];
      for (var i=0;i<imgs.length;i++){
        if ((imgs[i].className==imgClass)){

          // if the image doesn't have an id create one
          imgs[i].id=(imgs[i].id)?imgs[i].id:"img2swf"+i;
          imgIDs[i]=imgs[i].id;
      } }
      for (i=0;i<imgIDs.length;i++){
        flashInset(imgIDs[i]);
      }
    });
  }

  return{
    init:init
  };

}();

img2swf.init();

Adding Flash variables

As part of the latest update I added the ability to state Flashvars. Albeit in a separate script statement. Just add the following script anywhere on the page, but it must run prior to img2swf.js:


<script>/*<![CDATA[*/
  var flashVars="VARS IN HERE";
/*]]>*/</script>

Note: This method provides only one flashVar which is shared by all Flash insets on the page.

I recently used this method to embed a video player into a Tesco mini-site for AMD

Embedding Flash directly without JavaScript support

author: david grudl uploaded: 5th October 2008

Not recommended but added to supply a complete picture of the alternatives.

Caveat: This method did not work on the Tesco ASP or ASPX servers due to the server detecting both object element declarations and ignoring the conditional comments. The workaround I empolyed was to duplicate the whole object. Once for non-IE and once for IE.

If the Flash must be made available, even when JavaScript isn't, then maybe the following technique may be employed:


// author: David Grudl - http://latrine.dgx.cz/how-to-correctly-insert-a-flash-into-xhtml
<!--[if !IE]> -->
<object type="application/x-shockwave-flash" data="movie.swf" width="300" height="135">
<!-- <![endif]-->
<!--[if IE]>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" width="300" height="135">
  <param name="movie" value="movie.swf" />
<!--><!-- -->
  <param name="loop" value="true" />
  <param name="menu" value="false" />
  <p>This is <b>alternative</b> content.</p>
</object>
<!-- <![endif]-->

The solution doesn't get past the Eolas issue in IE, where you have to click to activate the Flash object, but adding the following script will sort that:


var obj=document.getElementsByTagName("object");
for(var i=0;i<obj.length;i++){
  if(obj.type!="application/x-shockwave-flash"){
    obj[i].outerHTML=obj[i].outerHTML;
  }
}
if(!obj.type){obj[i].outerHTML=obj[i].outerHTML;}

A bare-bones no-javascript reliance demo. For more info please see the original article: How to correctly insert a Flash into XHTML with a byline of without reliance upon JavaScript.

The Flash object will appear under the maximum number of conditions, even without JavaScript support. but please be aware that systems that do not support JavaScript are also unlikely to support current versions of Flash.

Personally speaking I prefer the JavaScript replacement technique where if the ideal conditions are not met then supply alternatives. But it's up to you and the specific case in which your involved.

Audio, video and photo galleries

I use a similar method to embed audio players, photo galleries and video. A few more details are required though.

This article continues with Embedding Flash video

Further reading

History

26th May 2010:

  1. Removed the requirement for image to have an id.
  2. Replaced Flash embed method.
  3. Parent width & height set to minimise layout disturbance.
  4. Function and variables inside a closure.
  5. Transparent wmode added as default (allows html overlays).
  6. A separately declared single Flashvar implemented.