Article
A New Image Replacement Technique: The State Scope Method
Page: 1 2
Checking Whether Images Are Enabled
In our script, we’re going to test for the presence of an image. I wanted to avoid testing this on an image on the server, which would incur an additional HTTP request. However, it seems that avoiding this overhead required a little creativity.
In most browsers, an Image object can be instantiated and sourced to an invalid URL (http://0). Then, we can easily determine if images are enabled, because if they are, the onerror event will trigger. At the beginning of our script, we set up a new Image object:
var img = new Image();
However, there are two oddball browsers that complicate this approach; in Gecko-based browsers, the onerror event is always triggered regardless of whether images are enabled, so it fails to work. Fortunately, there’s a workaround. By attaching an invalid background image to the document’s HTML element, and then reading back its style with the getComputedStyle method, the background-image CSS property will read none or url(invalid-url:) if images are disabled:
if (img.style.MozBinding != null)
{
img.style.backgroundImage = "url(" + document.location.protocol + "//0)";
var bg = window.getComputedStyle(img, '').backgroundImage;
if (bg != "none" && bg != "url(invalid-url:)" || document.URL.substr(0, 2) == "fi")
{
document.enableStateScope("images-on", true);
}
}
The other challenging browser is Safari. If a request is made to an invalid URL, Safari reports an error in the status bar. The layout will be unaffected, but if the user has the status bar turned on, the error screams unprofessional. Again, I’ve created another workaround. If an image is sourced to a 1x1 pixel GIF encoded as a data URI, the width of that image will be zero if images are disabled. Here’s how we test for it in Safari:
else
{
img.style.cssText = "-webkit-opacity:0";
if (img.style.webkitOpacity == 0)
{
img.onload = function()
{
document.enableStateScope("images-on", img.width > 0);
}
img.src =
"data:image/gif;base64," +
"R0lGODlhAQABAIAAAP///wAAACH5BAE" +
"AAAAALAAAAAABAAEAAAICRAEAOw==";
}
}
Finally, for all other browsers, we can simply test for an onerror event triggered by the Image object we instantiated at the beginning:
else
{
img.onerror = function(e)
{
document.enableStateScope("images-on", true);
}
img.src = "about:blank";
}
This all works even when the user is disconnected from the Internet. A small caveat, though—in Firefox 3, images with a file:/// URL will always be loaded even if you have images turned off. In this case, it’s better to test from a web server you can access using HTTP.
State Scopes Are Switchable
As an added bonus, because state scopes can be switched on and off, it’s easy to create a system that lets you switch between text and image replacements with one click (you’ll see this working in the example file). Depending on what software you’re using to write your CSS, this can be helpful during development.
The main reason the class name is added to the html element, instead of the body element or a child of it, is that the body element needs to be fully loaded before it can be manipulated. If the images-on class name is added to any element other than the html element, an undesirable flicker occurs when enabling the state scope. Also, it’s a popular practice to place CSS class names on the body element to restrict certain CSS rules to certain pages. This practice could be hampered if the images-on CSS class was also set on the body element.
What This Means for Web Developers
For any web designer that has been wanting to use image replacement, but has decided against it because of the associated complications, this technique can make a monumental difference in the way you build web sites. For everyone else, it’s a great way to improve the robustness of your site.
When you consider your reasons for using text inside an image, image replacement should be used as often as you can—whether that’s a company logo, a fancy title, or an “Add to Cart” button. There really only is one appropriate place for the image tag: when you are truly describing an image! Semantically, images are photographs and drawings, rather than pictures of text generated in Photoshop. And when you consider techniques like CSS sprites, search engine optimization, and ease of maintenance, working with CSS background images is much more desirable than working with image elements.
In my opinion, image replacement is the most critical part of CSS construction—which is why I’ve spent so much time trying to find a better way to implement it. I hope this information can help you build a better web site.
(Photo credit: JR3)