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 on November 8th, 2006

Realazy

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

2 . Jesse Skinner on November 8th, 2006

Jesse Skinner

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

3 . Tom on November 8th, 2006

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 on November 20th, 2006

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 on December 17th, 2006

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 on December 18th, 2006

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 on December 27th, 2006

Bliss

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

8 . trovster on January 24th, 2007

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 on January 25th, 2007

peter

brilliant!
i like your solving problem method.

Comments are closed, but I'd still love to hear your thoughts.