If you didn’t hear, text on a website is better than an image. Images have their place, but many people use images where text should be. In recent times, people have been using a technique called image replacement to replace text with an image. Typically, there are crazy hacks that involve embedded elements, but there is an easier way.
Before I get to that, I want to clear up when I think it is good to use images and when it is good to use image replacement.
It’s good to use image replacement when the object in question is, simply, an image. For whatever reason, I always picture a horse, silhouetted against a brilliant pink sunset, running through a grassy field on cliffs above the ocean. What I did there was describe the image, which goes in an
alt attribute. My rule for using images is: if the proper description is a sentence (or longer), use an image with an
alt. If the proper description ends up being a few words (e.g. Amazon Logo), use image replacement with semantic markup.
Most of the time, fancy heading text (in
h1s, etc) and logos are prime targets for image replacement. Logos typically appear at the top of the screen and, to me, seem to be the top-level heading of the site. Other times, people want their heading text to be in fonts that aren’t web safe. This is a great time for image replacement, because it retains the semantic value and accessibility without some level of complication (that is, the heading isn’t the alternate text inside an image, it’s just the text).
There are tons of ways to do image replacement. Until recently, I was doing it the way I think most people do it (sorry for the inline CSS; I’m trying to avoid confusion):
1 2 3
<h1 style="background-image:url(myheading.png); width:100px; height:100px"> <span style="position:absolute; margin-left:-9999px;">My Heading</span> </h1>
This is a perfectly valid way to do the markup. The only problem is that it has that extra
span in there. It’s semantically valid (since
spans don’t mean anything, but it’s one more level of complexity (that is, the heading is the text inside of the
span), which is what we wanted to avoid.
Instead, I’ve been doing it this way1 (again, sorry for the inline CSS):
<h1 style="position:relative; width:100px; height:100px; clip:auto; overflow:hidden; line-height:210px; font-size:10px; background-image:url(myheading.png);">My Heading</h1>
The relative positioning makes it possible to clip and hide the overflow of the element. So, we set our height and width to that of the image that will replace the text. We then come up with a sane image height (I’ve used
10px because the text doesn’t have to resize since it is hidden and because the default
don’t display text smaller than setting in browsers should be lower than this by default (if there is any worry, we can use a larger font size). Then, we set the line-height to the site of the image plus the size of the font (this seems to hide the font just out over the height of the element). Using the line height, we can also assure that the text will be hidden since it will be below the visible area instead of to the left or above it.
There you have it: yet another way to do image replacement. Is it better? Maybe. It reduces the complexity of the markup, making it less bloated and a bit more efficient, semantically if nothing else. However, it increases the work that needs to be done on the CSS side. With this we have a little math to do, and a little bit more to type. To reduce the extra typing a class could be created to handle the
font-size with the second class setting up the stuff that changes per image. In the end, do what suits you best. I’ll be doing it this way.
As a warning, the only problem I’ve run into2 was if I set the line height too high, Internet Explorer would have some rendering problems. I don’t remember exactly what happened, as it’s been awhile since I tested this on a real browser. I’ll be sure to update this post the next time I am able to test.
Wait! This is sort of untrue. I thought I was doing this one way, but it turns out I was wrong. I was using something with
position: absolute, which has some positioning problems if the user is unaware of how absolute positioning works. I’m pretending I’ve been doing it this way because I like it better.
Technically, it was a problem with the way I was doing the absolute positioned way. I’m leaving the warning in just in case for now.