Using a transparent image as an icon fallback

Sometimes designs contain button styling that is difficult to create with CSS alone. The “official” way of dealing with this is to either use an image button (<input type="image" src="button.png" alt="Ok" />) or put the image in a button element (<button><img src="button.png" alt="Ok" /></button>).

However if the graphic you want to show instead of the button is part of a sprite image, or if you want to display a different image when the button is hovered over or receives focus, that won’t work. In these cases it can be tempting to just use a background image and move any text the button contains out of the way by positioning it off-screen or applying a bit of text-indent. Or even worse, use no text content at all. Using no text content at all is obviously no good to anyone who can’t see the image, like screen reader users. And hiding the text causes problems if the image can’t be displayed.

Much of this is covered by Nicholas C. Zakas in Making accessible icon buttons, and I thought I’d talk a bit more about a technique he mentions that I use in these situations – the transparent one pixel image.

The transparent one-by-one pixel image

Using a transparent one-by-one pixel image feels a bit like going back in time to 1998, when the Web was full of transparent images used as spacers inside table cells to control layout sizes. But this time it’s there for a better reason.

As Nicholas describes in his blog post, using a transparent image lets you use CSS to place an icon on the background of a button while making sure the button contains real text (the alt text of the input or img element, depending on whether you’re using <input type="image"> or a button element with an img element inside. This makes it possible for screen reader users to understand the purpose of the button. One additional benefit this technique has, though admittedly it is an edge case, is that it benefits users that happen to have images off. Well, at least sometimes, in some browsers.

Theory vs. practice

Theoretically, alt text should be exposed when the image cannot be displayed. In practice this doesn’t always happen.

To test when this actually works I set up a Transparent image fallback demo page with a few examples of buttons using transparent images, either by referencing a real image file or by using a data-URI. Unfortunately, no browser that I have checked in does exactly what I think it should when images are disabled.

  • Firefox displays the alt text and does not clip it if it doesn’t fit inside its element. What Firefox does not do is display alt text for images whose url is a data URI.
  • WebKit browsers (tested in Safari, Chrome and iCab) only display alt text if the image URL is broken and the alt text will fit on one line within the space occupied by the missing image. If images aren’t displayed because the user turned off images, there is no indication at all (other than the empty space where the image would have been) that an image is missing.
  • Opera displays the alt text for images that reference a file as well as for those that use a data URI. However it clips the text if it doesn’t fit inside its element. I suppose once Opera switches to WebKit this will change for the worse.
  • IE does what Opera currently does, but adds an icon before the alt text which increases the risk of the text getting clipped.

In my opinion, the correct behaviour would be to display alt text without clipping it (like Firefox does) and also do this for images with data URI:s (like Opera and IE do, but without the icon that IE adds). See also Visual display of alternative text.

So, this technique is not perfect in practice, but by using it at least you’re giving browsers a chance to help users that can’t see the image.

Finally, unless the icon or symbol you use instead of text is extremely obvious and cannot be misinterpreted, consider adding a title attribute for mouse users (and make the title text appear when the button gets keyboard focus).

Posted on April 30, 2013 in Accessibility, Browsers, CSS

Comments are disabled for this post (read why), but if you have spotted an error or have additional info that you think should be in this post, feel free to contact me.