Using basic CSS there are various ways to replace text with images, but most of these methods have drawbacks. These drawbacks become even more apparent when you are using image replacement in links (such as in navigation items). A primary reason for using image replacement is to aid in accessibility, but many of the common ways to replace text have accessibility issues. In an effort to choose one of these methods as our company's standard, I evaluated the most common image replacement techniques while creating a site's primary navigation. I thought it might be informative to show the process involved in choosing the option I believe to have the least serious drawbacks.
This may get a little complicated, so I'll first start with some simple examples of image replacement.
Replacement Method #1
Let's start with this code:
<h1><span>About Us</span></h1>
When this header is rendered, what we'd like to see happen is the text 'About Us' disappear and be replaced with a nice image we've made. The easiest way to do this would be to apply a background image to the h1 tag and set the span tag to not display.
h1 {
background-image: url(images/about_us.gif);
width: 200px;
height: 100px;
}
h1 span {
display: none;
}
Unfortunately, setting display to 'none' causes most screen-readers to ignore the text, so nothing gets read at all. In addition, if the user turns off images in their browser but leaves CSS on (a common thing to do on slow connections or handheld devices), the header effectively ceases to exist.
Replacement Method #2
Using the same HTML, this rather serious drawback can be overcome by modifying the CSS a bit.
h1 {
background-image: url(images/about_us.gif);
width: 200px;
height: 100px;
}
h1 span {
display: block;
overflow: hidden;
height: 0;
}
Now the span is set to display block, but is effectively hidden from visual browsers by setting the height to '0' and making sure the overflow is hidden. The background image still shows clearly though and in screen-readers, the text will still be read. Unfortunately, the header still ceases to exist for all intents and purposes if images are disabled but CSS left enabled.
Replacement Method #3
Yet another method removes the need for the span scaffolding altogether, leaving our HTML happily simple and semantic.
h1 {
background-image: url(images/about_us.gif);
width: 200px;
height: 100px;
text-indent: -9999px;
}
Here the background image is still applied to the h1 tag as before, but the text is cleverly removed from view in visual browsers by indenting the text negatively a ridiculous amount. In visual browsers the image display normally but the text is moved far off the screen (probably about 10 feet or so to your left), effectively hiding it. However, screen-readers will still read the text normally. Unfortunately this method, while simple and elegant, still suffers the same drawback as the previous method -- it renders the header tag useless if images are disabled while CSS is still being used. The negative text-indentation trick also has another drawback when links are being used, but I'll get to that later.
Replacement Method #4
The final method of image replacement suffers none of the drawbacks seen in these previous methods. Images display normally in visual browsers with the text hidden, screen-readers read the text normally and the header still renders if images are disabled (whether CSS is used or not). We start with this rather counter-intuitive HTML.
<h1><span></span>About Us</h1>
We're back to using a span tag, but in this HTML, the text is actually outside of it. Our CSS gets a little trickier.
h1 {
width: 200px;
height: 100px;
position: relative;
}
h1 span {
background-image: url(images/about_us.gif);
width: 200px;
height: 100px;
position: absolute;
top: 0;
left: 0;
}
What's going on here is the h1 and the span contained within are both being set to the same height and width. The relative and absolute positioning of the tags allows us to place (in layer terms) the span on top of the h1. Effectively, the text within the h1 is hidden behind the background image of the span. The text will be read normally by screen-readers and turning off images will simply reveal the text underneath. The only drawback to this option is that the width of the text underneath has to be equal to or less than the width of the image replacing it. Otherwise, parts of the text will hang out from underneath the image like feet sticking out from a blanket that's too short. However, in most cases this will not be a problem and in those cases where it is, the size of the text could be manipulated through CSS. If a user bumps their text size from within their browser too high, this will obviously start to become more worrisome -- but this seems to be the least offensive of the drawbacks from all of these methods.
Now lets see what happens when we start to use these techniques within a site's primary navigation where our images need to be anchors. Below is what we're trying to create should look like. Four navigation buttons with dark blue roll-over states.
To achieve this goal, we'll need to create four images. We could make eight (an on and off state for each of the four menu items), but rather than be forced to preload images let's just put the on and off state right into the same image. So here's what the image for the first nav item would look like.
But which replacement method to use? When originally building and testing this navigation, I rejected Method #1 straight-away since it offers no real accessibility benefits. So I started with Method #2. It worked fairly well, but I was unhappy with having to use span tags and the fact that the site becomes unusable if images are disabled (with CSS enabled). Further research led to me to Method #3, which seemed like a big winner. Clean HTML with no span tags and a nifty negative indentation trick -- what's not to love? Sure, it still has that problem with the navigation becoming unusable when images are disabled, but so did the first two methods.
I was content to leave the navigation like this until I started testing it in Firefox. Many browsers (like Firefox) outline links when you click on them or use other methods of link selection (like using Tab in keyboard navigation). What I expected was something that looked like this:
When tabbing over to or clicking on the 'Mission' button, it gets a subtle dashed outline. What I found though using Method #3 was something like this:
In most browsers, the highlighted outline stretched all the way from the nav button to the edge of the browser window (and, in theory, 9000 or so pixels more to the left). This really wasn't acceptable. The problem didn't show up in IE, but who really uses that anyway?
Further research led me to Method #4, which I started playing around with in an attempt to get it to work with anchors. Following the example from above, the HTML for the complete navigation would look something like what I have below. The text and span tags go within our primary tag (here, a list item). The anchors go around both the text and span.
<div id="navigation">
<ul>
<li id="navMission"><a href="#"><span></span>Mission</a></li>
<li id="navNews"><a href="#"><span></span>News</a></li>
<li id="navDonors"><a href="#"><span></span>Donors</a></li>
<li id="navStaff"><a href="#"><span></span>Staff</a></li>
</ul>
</div>
The CSS gets a bit complicated, but I've included the important parts below (for the sake of brevity, I've only included the CSS for the first nav item).
#navigation ul li {
float: left;
display: block;
height: 21px;
position: relative;
}
#navigation a:link,
#navigation a:active,
#navigation a:visited,
#navigation a:hover {
display: block;
height: 21px;
line-height: 21px;
font-size: 9px;
}
#navigation span {
position: absolute;
top: 0;
left: 0;
height: 21px;
}
#navMission {
width: 67px;
}
#navMission span {
background: url(images/nav_mission.gif) no-repeat 0px 0px;
width: 67px;
}
#navMission a:link,
#navMission a:active,
#navMission a:visited,
#navMission a:hover {
width: 67px;
}
#navMission a:hover span,
#navMission a.selected:link span,
#navMission a.selected:visited span,
#navMission a.selected:active span,
#navMission a.selected:hover span {
background: url(images/nav_mission.gif) no-repeat 0px -21px;
}
Like in our previous example, what's happening is the text and the span are being set to the same height and width, and the background-image of the span is being placed on top of the text, effectively hiding it from view like two stacked notecards.
The anchor tag is being applied to both of them and a hover state repositions the background image of the span to show the dark blue "active" state when moused over. As long as the text underneath isn't too long or sized too large, in most cases this should work fine. Further, the links still work when you disable images whether CSS is enabled (as shown below) or not.
Currently this seems to be the most accessible way to do image replacement. At least until things like the CSS3 content property (which replaces the contents of an element with something else) are supported in the majority of browsers. Since this seems unlikely in the near future, we'll likely be relying on tricky work-arounds and clever hacks for quite some time.
Below you can see the fully functioning navigation. You can turn off images and CSS in your browser and see how it looks for yourself. If you so desire, a quick peek at the source code of this page should reveal all the HTML and CSS involved. If you see a problem with this method or know of a more elegant solution, please leave a comment.
Comments
Mon, 10.11.2008 11:25
What about looking at the 'Accept-Language' header sent by the browser?
Mon, 03.11.2008 13:52
Thanks for the feedback. In our review of how other multicultural sites have addressed this issue, we have noticed that [...]
Mon, 03.11.2008 13:20
Splash pages aren't good for SEO, really BAD choice to make.
Thu, 09.10.2008 16:01
Firefox also has a plug in called pencil https://addons.mozilla.org/en- US/firefox/addon/8487 That does something [...]
Thu, 09.10.2008 15:25
We have also experienced problems with JS conflicts when using Jquery library with SiFR. No doubt SiFR renders [...]
Thu, 09.10.2008 14:39
I'd be interested to see how you could see using this for anything. Why don't you write me up a report
Tue, 23.09.2008 19:27
Hi There, How do I add one of these symbols to my blog? I'd like to include the symbol at the title of any blog [...]
Wed, 03.09.2008 09:53
FF messages