There don't seem to be any browser incompatibilities.
See Shaun Inman's IFR for another technique, this one using Flash.
Recently there has been much discussion about the "Fahrner Image Replacement". Although I liked the concept, I disliked the countless CSS variants that have popped up, because they are inherently unsafe and hacky. I feel we should use JavaScript instead of CSS. This page explains my script.
The idea of FIR is simple: Initially a page is served with text as the content of its headers. However, some clever (or not so clever) hacks are applied that hide this text and show an image instead. Theoretically browsers that can't handle advanced CSS, as well as screen readers, should not execute the replacement. Therefore the headers would remain accessible under all circumstances.
Unfortunately all CSS variants are making assumptions about screen reader behaviour. Joe Clark has admirably summarized the problem and his research. Screen readers turn out to support the CSS bits that everyone assumed they wouldn't support, so they hide the text. They can't show the image either, so accessibility is severely compromised. Clark's conclusion is that any CSS variant is inherently unsafe.
When I read a question about using JavaScript to enhance FIR, I realized that everyone was approaching this problem from the wrong way. We shouldn't use CSS at all to replace text by images. Instead, such a replacement job is a typical JavaScript task. In fact, it's ridiculously easy.
Nonetheless I'm not any better than the myriad CSS hackers who have preceded me: I make assumptions about screen readers. Although to me my assumption seems safer than all others, it may still be totally wrong. That's the chance you take when writing code for user agents you can't test in.
My assumption: Screen readers do not download images.
All h3
texts on this page are replaced by images, if your browser allows it.
The images are not examples of rarified design beauty. That's because I'm not a designer.
If you switch off images your browser will show normal h3
s.
I add an id
attribute to any h3
that should be affected. It contains
the source of the image to be displayed instead of the text. This script assumes that every h3
with an id
should be replaced by an image.
<h3 id="fir_script">The script</h3>
This h3
expects the image pix/fir_script.gif
for a replacement.
Then I run this script onload
.
function init() { var W3CDOM = (document.createElement && document.getElementsByTagName); if (!W3CDOM) return; var test = new Image(); var tmp = new Date(); var suffix = tmp.getTime(); test.src = 'pix/fir_assumptions.gif?'+suffix; test.onload = imageReplacement; } function imageReplacement() { replaceThem(document.getElementsByTagName('h3')); } function replaceThem(x) { var replace = document.createElement('img'); for (var i=0;i<x.length;i++) { if (x[i].id) { var y = replace.cloneNode(true); y.src = 'pix/' + x[i].id + '.gif'; y.alt = x[i].firstChild.nodeValue; x[i].replaceChild(y,x[i].firstChild); } } }
onload you should run the function init()
.
function init() {
The first thing we do is checking for W3C DOM support. If it's absent we stop the script.
var W3CDOM = (document.createElement && document.getElementsByTagName); if (!W3CDOM) return;
Detecting W3C DOM support is not enough, though. We also have to see if the browser supports images. If it doesn't our script shouldn't run, since it would create all kinds of odd effects.
Therefore we generate an image and set its src
. This is a classic
preloading trick: the browser now fetches the image. This is the only support detection we need.
If this test image loads succesfully, the browser supports images. I assume
that a browser that doesn't support images doesn't download them, either.
So we activate the main image replacement routine only when this image has been loaded, ie. after its
load
event has taken place.
A browser problem here. If you return to this page by using the Back button, Explorer on Windows does
not fire the onload
event of cached images. Therefore we have to make sure that it
fetches a new image every time by adding a suffix that contains the current time in milliseconds.
I don't like this feature of the script, it causes unnecessary HTTP requests, but at the moment I don't see a way around it.
var test = new Image(); var tmp = new Date(); var suffix = tmp.getTime(); test.src = 'pix/fir_assumptions.gif?'+suffix; test.onload = imageReplacement; }
A reader suggested setting a cookie to keep track of the browser's image handling. If cookies are turned off, we default back to the suffix. Good idea!
Once the test image has been loaded, it's safe to do wholesale image replacement. The function
imageReplacement
is called. It's an intermediate function to allow you to define several
areas of the document where images should be replaced. This example script just replaces h3
s.
function imageReplacement() { replaceThem(document.getElementsByTagName('h3')); }
However, if you'd also like to replace, say, all links in div id="nav"
, do
function imageReplacement() { replaceThem(document.getElementsByTagName('h3')); replaceThem(document.getElementById('nav').getElementsByTagName('a')); }
The function replaceThem()
handles the actual image replacement. It is handed an array
which it searches for elements with an id
. If it finds one, the script replaces the
element's firstChild
(the text node containing the text) for an image with a name that's
similar to the id
.
To be on the safe side I also set the alt
attribute. Theoretically it's unnecessary, since
images will shown only when the browser supports images, but better safe than sorry.
function replaceThem(x) { var replace = document.createElement('img'); for (var i=0;i<x.length;i++) { if (x[i].id) { var y = replace.cloneNode(true); y.src = 'pix/' + x[i].id + '.gif'; y.alt = x[i].firstChild.nodeValue; x[i].replaceChild(y,x[i].firstChild); } } }