Coding with Jesse

Replace text with an image using CSS

November 7th, 2006

Let's say you want to have a logo on a page, but you'd really like to use an <h1> with some text for the header in the HTML. Or maybe you like to use images for all your titles, but would still like to have plain text inside header tags in your HTML.

There are a number of reasons for wanting to do this, namely accessibility and search engine optimization. I talk more about this in my post Writing Semantic HTML.

The problem is: How do you hide the text? I think the most popular technique is to wrap the text with a <span> inside the header tag, then use some CSS to 1) hide the text, and 2) use the header tag as an image. Something like this:

<style type="text/css">
h1 {
    width: 500px;
    height: 100px;
    background: url(my_header_image.gif);
}

h1 span {
    display: none;
}
</style>

<h1><span>My Great Header</span></h1>

Unfortunately, this technique makes us add an extra tag to our markup, and we all know that every time we use an unnecessary tag, a puppy dies. Either that, or we end up with ugly, unnecessarily bloated HTML.

Well here's another technique which hides the text just by using CSS. The text will still be readable by screenreaders and search engine spiders, but will disappear like magic for everyone else:

<style type="text/css">
h1 {
    width: 500px;
    height: 100px;
    background: url(my_header_image.gif);
    overflow: hidden;
    line-height: 500px;
}
</style>

<h1>My Great Header</h1>

This technique works by pushing the text down inside the header with a rather large line-height (it must be at least twice the height). Then the overflow: hidden hides the text since it's overflowing.

Now isn't that better? No puppies were harmed, and we end up with slightly cleaner and shorter markup.


Interested in web development? Subscribe to my newsletter!

Comments

1 . Realazy at 2006-11-08T13:44:21.000Z

Realazy

Why not use <code>text-indent: -999em;</code>(any large value), it's more simple.

2 . Jesse Skinner at 2006-11-08T14:10:29.000Z

Jesse Skinner

Yep, good call. I like that even better. Thanks!

3 . Tom at 2006-11-09T01:34:14.000Z

Tom

Personally I prefer a solution with which I can have a virtually limitless amount of text in the <h1> tag - neither of your solutions allow for that. I tried both using about four paragraphs of text and had problems with both.

Instead I use the following:

h1 {
width: 500px;
height: 0px;
background: url(my_header_image.gif);
padding-top: 100px;
overflow: hidden;
}

4 . trovster at 2006-11-20T17:21:55.000Z

trovster

Why would you use height: 0px then a padding-top?

I prefer the Phark method (text-indent: -9999px; or any arbitrary large negative figure) to the Gilder/Levin image replacement technique (the one mentioned with the extraneous span).

I don't know why you'd have problems with 'limitless amount of text', but the method below allows for that.

Personally this is how I do it:

h1, p.welcome, ul#nav li a {
display: block;
overflow: hidden;
font-size: 0.0; line-height: 0.0;
text-decoration: none; text-indent: -9999px;
background: transparent no-repeat 0 0;
}
h1 {
height: 20px; width: 500px;
background-image: url(header.img);
}
p.welcome {
height: 150px; width: 350px;
background-image: url(welcome.img);
}

This code easily allows for more elements to be replaced. Simply add the selector to the main replacement code, then create a separate declaration with the height, width and path to the appropriate image.

The display: block allows for the image replacement to be used on inline elements (such as anchors) with no extra code. The 0.0 on font-size and line-height are for bugs in the validator (!). And the overflow: hidden; trims the unsightly long 'focus halo' introduced in Firefox 1.5, so that is only the width of the content.

5 . Jesse Skinner at 2006-12-17T07:49:44.000Z

Jesse Skinner

I've been using Tom's method for some time now and it's really fantastic. It avoids relying on any browser bugs or using arbitrarily large numbers, and just does exactly what you want. Thanks, Tom!

6 . trovster at 2006-12-18T11:44:31.000Z

trovster

Not sure how the method I suggested is relying upon browser bugs. Also, the 'arbitrarily large number' doesn't have to be -9999px;, just the width of the area you're replacing. Because these sizes vary, you use a number which you're unlikely to exceed. You could, infact, use -1024px; if you so wished. As I doubt you're going to replace elements with widths larger than that size.

7 . Bliss at 2006-12-27T10:52:46.000Z

Bliss

In case, i wish to give hyperlink to the h1?

8 . trovster at 2007-01-24T18:54:54.000Z

trovster

@ Bliss: Then simple use the selector h1 a {} in the code I provided above. The generic code adds display: block, so you can automatically use it on inline elements and it still works...

9 . peter at 2007-01-25T05:15:10.000Z

peter

brilliant!
i like your solving problem method.