Why ALA's "JavaScript Image Replacement" is Very Bad

Written on 24 November 2003.

On this place, I originally launched a savage attack on Christian Heilmann's article. Remarks by Tom Dell'Aringa and Patrick Griffiths caused me to rewrite it. They rightly pointed out I was too agressive and hostile, and that this tone of voice drowned out the points I was trying to make.

This second version softens its tone towards Heilmann, but is considerably harsher towards A List Apart.

My original article remains online for historical purposes.

See also the comments on A List Apart for a complete overview of this article's genesis.

In its 164th edition, A List Apart has published an article about JavaScript Image Replacement, a technique I seem to have invented. Unfortunately the script it presents is severely besides the mark, or, in plain speech, very bad.
I conclude that ALA should not publish any JavaScript articles at all, since it seems to be incapable of judging them.

At the end of October 2003, scant days before launching this site, I realized that the much-publicized Image Replacement technique uses the wrong tool. While dozens of web developers have created CSS versions, I feel that image replacement should be done by JavaScript.

JavaScript Image Replacement (JIR, inevitably) was born. I did some serious theoretical thinking and published my own script to give an example of how it could work.

A month later Christian Heilmann published his JavaScript Image Replacement on A List Apart. I feel that his script is inconceivably worse than my own for several reasons I'll describe later on. I feel that by publishing this article the ALA editors actively support an irresponsible way of using JavaScript, something that is unworthy of this famed webzine.

Although I feel a bit defensive about JIR because it's my idea, anyone who knows this site also knows that I'm generally not shy about sharing my ideas and that I allow anyone to improve on them without any boring copyright notices whatsoever.

This reaction, and especially my earlier savage version, was spurred by the fact that someone writes an article about my idea, on ALA of all places, and doesn't even notice that there are fundamental issues to be considered, or that his script is just plain bad.

This thoughtlessness, and not the fact that he tried to 'steal' my idea, was what set me off. Feel free to use my ideas in any way you like, but please try to understand what they're about first before publishing them on a major webzine.

Now let's see exactly why this article is bad.

Theory

The theoretical part of the article doesn't mention the real questions at all. The real point is not the script or the XHTML that you use, but whether it's preferable to replace images by CSS or by JavaScript.

This touches on very important questions for the near future: which line divides CSS and JavaScript? Which functionality belongs in the presentation layer, which belongs in the behaviour layer? Any image replacement technique is merely a case study that might help us solve these questions.

I have no answers to these questions, in fact my study has just barely begun. I feel, though, that they should be prominently mentioned because they are far more important than the actual script.

In addition, the CSS FIR debacle teaches us valuable lessons about assuming things about user agents. Heilmann does not state his assumptions, which is very dangerous when we deal with unknowable user agents like screen readers and mobile phones.

Coding style

Heilmann uses a JavaScript array to store the data saying which header should be replaced by which image:

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

I intensely dislike arrays because they easily turn into a maintenance nightmare. We don't need them any more; the W3C DOM offers far superior ways of storing script data.

I myself use custom attributes in the headers themselves to store this data:

<h3 replace="fir_script">The script</h3>

I feel that this solution is superior to arrays, because it gives us a clean way of adding script data to the XHTML.

The problem is of course that custom attributes are not allowed in XHTML. Personally I don't care, but I know that others will care and will search for another solution. One solution could be to store the data in a valid attribute, like id.

Another solution would be to use a custom namespace, but at the moment of writing I'm unsure how they work, and whether they will be accepted by a W3C validator, even when the author properly includes his custom DTD.

So far it's a matter of coding style. Later on we'll see, however, that this data array may cause serious problems.

Nice extension

Heilmann's next step improves on my script. He goes through all possible headers that might exist on the page by getting them all by tag name. Nice extension. His object detection is flawless, too.

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

Nonetheless this single good point doesn't save the article.

The main script

The main script, the script that actually does the replacement, contains many errors.

function scanandreplace(h1s,tag){
  for(i=0;i<h1s.length;i++){
    for(f=0;f<replaceImages.length;f++){
      chunks=replaceImages[f].split(’|’);
      thish1=document.getElementsByTagName(tag)[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];
        thish1.replaceChild(newImg,thish1.firstChild)
       }
      }
    }
  }

Sloppy editing

The ALA editor was asleep while preparing the code examples. Did you spot the syntax errors?

if(thish1.firstchild.nodevalue==chunks[0]){

should of course read

if(thish1.firstChild.nodeValue==chunks[0]){

And

newimg.setattribute(’alt’,chunks[0])
newimg.setattribute(’src’,chunks[1])

should of course read

newimg.setAttribute(’alt’,chunks[0])
newimg.setAttribute(’src’,chunks[1])

Finally the crucial line

thish1.replaceChild(newImg,thish1.firstChild)

is missing from the complete code example in the middle of the article.

In a technical JavaScript article this is relatively unforgivable. Any copy-pastable code example should be free of syntax errors. Period.

Fortunately these errors don't occur in the line-by-line discussion that follows the complete script or on the example page. Nontheless ALA is being very sloppy.

Too many loops

Heilmann's script loops through all headers on the page, and that's of course necessary. However, for every header it finds it subsequently loops through the entire data array! In his example Heilmann uses only three images, making for a total of 9 comparisions of header text and data array. That's manageable.

When we use the script on a real-life page, though, and when we take into account that sooner or later someone will want to use it to replace not only the headers but also the main navigation links by images, this technical problem becomes much worse.

Let's say we want to replace 20 texts by images.Then you end up with 400 comparisions of header text and data array. Can you hear the browsers churning and panting to keep up? Can you imagine how much worse the problem becomes with 30 or 40 replacements?

Heilmann even ignored the basic precaution of adding a break statement to break off the comparision loop after the correct data has been found. This would have significantly reduced the number of comparisions.

This part of the script is not an example of well written, responsible JavaScript.

Image replacement

Finally, the actual image replacement is dangerously incorrect.

thish1.replaceChild(newImg,thish1.firstChild)

On my own page I clearly explain that you should not just insert the image into the document because this will have serious consequences.

IBM's Home Page Reader is built on top of Internet Explorer, and its product page states that it handles JavaScript. Therefore it might execute Heilmann's script and replace header texts by meaningless images.

Instead, I feel that we should wait until the image has been loaded before inserting it into the document. If the browser actually loads the image, we can be reasonably sure that it in fact supports the display of images. Then, and only then, it is safe to insert images.

Unfortunately the author does not address this problem at all. A pity, since it is the crux of JavaScript image replacement. How do you find out if a browser can handle image replacement? What happens when it doesn't?

What happens when a browser that doesn't support images runs Heilmann's script? It shows the ALT text.

Why don't we give no-image browsers a nice CSS-enhanced header text? Why do we have to put up with this ugly, avoidable bit of distortion?

ALA: stick to what you know

This whole article is very bad. It pays no attention to crucial theoretical questions, the script it presents is flawed on two major points, and the editor was asleep while preparing the code examples.

The worst part is: it doesn't even surprise me. The ALA staff is incapable of judging JavaScript articles. I first noticed this trend about two years ago, and in the intervening time ALA has not shown the slightest bit of improvement. In fact, I feel that since J. David Eisenberg's July 2000 article DOM Design Tricks II ALA has not published any good programming article.

When ALA presents articles about accessibility, design, usability, CSS or copy I read them with care. I was very, very happy with Joe Clark's brilliant refutal of CSS image replacement. I practically drooled when I read Douglas Bowman's Sliding Doors of CSS revelation. In fact, when I finished it I immediately read it again, and that's something I almost never do. I can't wait to use this technique in a commercial website.

That's the content I expect to find on ALA. Solid, serious articles that explore the very frontiers of our knowledge, offer interesting new viewpoints or novel techniques for creating simple, appealing websites.

In contrast, the average JavaScript article on A List Apart is mediocre at best. These articles do not break any new ground, the scripts are mediocre, theory usually absent. They consistently ignore the real, underlying questions in favour of a bunch of childish scripts.

Apparently the ALA editors cannot judge JavaScript articles on their merits because they lack the technical knowledge. That's fine with me, I can live with an ALA that only publishes guru-level articles about CSS, accessibility and usability.

But ALA should not try to do what it cannot do. If it cannot judge JavaScript articles, it shouldn't publish them. ALA demeans itself.

Worse, by publishing such articles ALA actively promotes a sloppy, irresponsible coding style that sharply diverges from the accessibility, web standards and structural coding the magazine purports to promote.

By emphasizing the wrong aspects of JavaScript and by refusing to consider theoretical questions it hinders JavaScript's growth towards a fully fledged client side behaviour layer, to stand next to the CSS presentation layer and the XHTML structure layer.

Finally it gives the wrong examples to thousands of beginning and intermediate web developers, who feel any ALA article can be trusted. ALA breaks this trust. Worse, it doesn't even notice it's doing it.

A List Apart editors, please do not publish any more JavaScript articles until you have added a competent JavaScripter to your editorial board. You're doing yourself, the values you stand for, and web development in general a singular disservice.

Update: Zeldman has announced that henceforth J. David Eisenberg will be ALA's technical JavaScript editor. I, for one, am happy with this decision. I fully trust I won't have to repeat this necessary attack on one of the best web development magazines in existence.

Unrelated note

One more note before we close this issue. It's so weird that I had to add it to the page for future reference, even though it doesn't have anything to do with scripts.

In his reaction to the hubbub caused by my article, Craig Saila wrote:

"Now with people being publicly ridiculed and insulted for trying to expand on an interesting idea, it’s only a matter of time before a someone is murdered with an ice pick in Mexico."

The ice pick stuff of course refers to Trotski, who was murdered in exactly such a way in 1940. Saila goes on to make a point that modern web development starts to resemble left-wing bickering.

The really weird thing is that, way back in 2000, when I published my first ALA article "Fear of Style Sheets, Part 3", Zeldman created a header image that showed ... Joseph Stalin, the man who told the ice pick to go stick itself in Trotski's head.

What a curious coincidence. It must mean something, but I don't know what.

I hope it's a good omen.