A List Apart

Menu
Issue № 164

JavaScript Image Replacement

by Published in CSS, HTML, JavaScript, Interaction Design · 57 Comments

As discussed previously on A List Apart, Fahrner Image Replacement (FIR), a technique developed to allow designers to use image-based typesetting while meeting accessibility requirements, only serves its intended purpose when screen readers misbehave.

The premise of FIR is simple: set the text-containing image as the background of an XHTML element and hide the corresponding plain text by nesting it in a span and setting the span’s visibility to hidden, or display to none.

Most screen readers, however, are clever enough to realize that text set to visibility: hidden or display:none should not be read.

That’s why Peter-Paul Koch came up with the idea to use JavaScript to replace plain text with image-based text (on the css-discuss mailing list), and that’s where the technique explained here comes in.

Why JavaScript?

There are already many solutions to the problem, each of them using CSS to hide, move, or stack the images and the text. The forum entries related to Joe Clark’s FIR article propose several.

By using JavaScript, we have an opportunity none of these solutions give us: the markup can be plain vanilla XHTML, with no need for any special IDs or CSS tricks in it.

Non-JavaScript users will simply see the headlines as they are, and designers still have the chance to style the plain-text versions with CSS.

The only users whose experience is negatively affected are those with JavaScript turned on and images turned off. These users will see the text replacement for the image. An exception are Mozilla users — but more on that later.

Enough talk, show us the goods

Take a look at the demo page and you’ll see the technique in action. This is achieved by using one script together with an array of image names.

replaceImages = new Array(
  ’About us|about.gif’,
  ’History|history.gif’,
  ’Contact Us|contact.gif’
  );function firdom(){
  if(document.getElementsByTagName && document.createElement){
    for (l=1;l<=6;l++){
      h1s=document.getElementsByTagName(’h’+l);
      scanandreplace(h1s,’h’+l);
      }
    }
  }
function scanandreplace(h1s,tag){
  for(i=0;i;
      if(thish1.firstchild.nodevalue==chunks[0]){
        newimg=document.createElement(’img’);   
        newimg.setattribute(’alt’,chunks[0])
        newimg.setattribute(’src’,chunks[1])
        // or newimg.src=chunks[1];
        }
      }
    }
  }
window.onload=firdom;

The array replaceImages needs to be defined either once in an external JavaScript or for each page individually. It tells the script which headline to replace with which image.

The text that will be replaced and the URL of the replacement image are separated with a “|”.

In the below example, any headline with the content “About Us” will be replaced with the image “about.gif”, any headline with the content “History” with ”history.gif” and so on.

replaceImages = new Array(
’About us|about.gif’,
’History|history.gif’,
’Contact Us|contact.gif’
);

All you need to know to use the technique is how to assemble this array. Then you can add the array to your page, include the script via its own script tag, and enjoy the graphical headlines.

If you are not familiar with the DOM and you don’t want to know about it, skip the next bit and proceed to “Where it fails.”

Under the hood — how it works

So you want it more technical, then? Okay, firdom() does the following:

First we check if our browser can deliver what we need by testing for DOM capabilities. This prevents old browsers from trying to do what they can’t.

if(document.getElementsByTagName && document.createElement){

Then we loop through all possible headline levels (<H1> to <H6>) and call another function, asking that one to find and replace all headlines with the current level.

for (l=1;l<=6;l++){
  h1s=document.getElementsByTagName(’h’+l);
  scanandreplace(h1s,’h’+l);
  }

This function, scanandreplace(), takes each one of these headlines and compares its content (the nodeValue of its first child) with the text preceding the “|” in each element of the array replaceImages.

function scanandreplace(h1s,tag){
  for(i=0;i;
      if(thish1.firstChild.nodeValue==chunks[0]){

If there is a match, we create a new image element and set its source to the text following the “|” in the current element of replaceImages.

To take an additional accessibility precaution, we set the alt attribute of the new image to the text of the headline.

  newImg=document.createElement(’img’);   
  newImg.setAttribute(’alt’,chunks[0])
  newImg.setAttribute(’src’,chunks[1])

All that remains to be done is to replace the original text content of the headline (its first child), with the newly created image — and voila, we have graphical headlines.

  thish1.replaceChild(newImg,thish1.firstChild)
      }
    }
  }
}

Where it fails: Mozilla’s method of imageless surfing

This technique works in every DOM-compliant browser. Without JavaScript, you will see plain-text headlines (search engines will also see and index the plain-text versions). With images turned off, you will see the alt text within headline elements.

That is, unless you use Mozilla. If you go to Mozilla’s web features, you see an option that allows you to stop “loading images.” If you uncheck that checkbox, Mozilla stops loading images. Oddly enough, it does not show the alt text either. This happens to every image, and also to our little routine here. At the time of publication, we don’t know of any workaround.

Gimme gimme gimme

You can download the script here. Watch its homepage for fixes and changes. Enjoy.

57 Reader Comments

Load Comments