Dave Woods - Freelance Web Design Warwickshire

CSS Image Replacement

Quite often when designing a website we’ll want to replace a heading using an image and there are various techniques to do this but what’s the best method for using a CSS image replacement technique?

Use an Image

The simplest way is to use an image and is probably the first solution that most designers will consider. As long an alt text is provided using the alt attribute of the img tag which is equivalent to the text in the image then it will also be accessible.

<h1><img src="image.gif" alt="Image Replacement"></h1>

The drawback of this is that search engines add very little weight to the alt attribute and therefore even though this is deemed as being a heading through the use of the h1 tag, the benefit of this is being lost due to the text being contained within the alt attribute.

Removing the Text

This is probably the most commonly used but shouldn’t be mistaken for using display: none; to hide the text as this is bad for screen readers.

If we add an extra span tag around the text then we can deal with the heading and text separately.

<h1><span>Image Replacement</span></h1>

and the css…

h1 {
background-image: url(image.gif);
background-repeat: no-repeat;
width: 256px;
height: 41px;
}
h1 span {
position: absolute;
left: -999em;
}

This has the benefit of including the text within the page which is displayed if CSS isn’t supported and is also visable to screen readers and to search engines.

Up until recently I’ve been using this method but considered the impact of this method on users who may be browsing without images. Unfortunately this is still quite common for users on dial-up connections who don’t want to use up bandwidth downloading images and the bad news is that using this method will simply give these users a blank space where the image should appear without so much as alt text to inform these users what they’re missing.

The Solution

The solution is slightly more complex but does enable all users to access the image or the text as well as benefiting the search engines.

The html is ever so slightly different to the previous example and just involves having an empty span tag before the text…

<h1><span></span>Image Replacement</h1>

Next we’ll do something very similar to the previous example and provide a width, height, background-image and font-size for both the h1 and for the span within it…

h1, h1 span {
width: 256px;
height: 41px;
background-image: url(image.gif);
font-size: 100%;
}

Now, we can do the magic and hide the text underneath the image so that when images are disabled, the text is left in its place instead…

h1 span {
display: block;
position: relative;
z-index: 1;
margin-bottom: -41px;
}

This works by positioning the span element over the top of the h1 element using relative positioning and the z-index. We need to change the display to block in order for the width and height to be applied to the span whilst also adding the margin-bottom rule to equal that of the height so that the text doesn’t appear below the image.

Finally, I use overflow hidden on the h1 element so that if the text size is increased in size, it won’t appear over the sides of the image. This can be done by simply adding the following rule…

h1 { overflow: hidden; }

An example of this working is available here…

Summary

As always, any questions, comments or other suggestions for css image replacement techniques are more than welcome.

27 comments on “CSS Image Replacement

  1. Dave Post author

    Hi Pegasuz,

    I presume you’re talking about the main logo for the page?

    I’d generally do this as good practice and link it to the homepage but this article is aimed more at the situation where you may have a number of different headings or sub headings on a page where an image would look cleaner and add variety to the page.

    You may also want to use this technique for navigation in which case it’s vital for any users without images available to be given an alternative in which case the final solution on this page would be ideal.

    Hope that makes sense?

  2. Michael

    Dave,

    What happens if a user disables images… and at the same time alters the text-size in the browser?

    Won’t the overflow:hidden get in the way?
    You did set a fixed width en height on the h1 element as well, no?

  3. Dave Post author

    Hi Michael,

    Yes, that’s the one drawback unfortunately of this method.

    You could of course not set the overflow and this would allow the text to flow out of its container however depending on the design, this could be quite undesirable.

    However, if the font size for the heading is set smaller than normal for a heading then it should usually fit within the container even if the font size is increased. In the example above, the font size can be increased twice (in Firefox) and it still fits within the box.

    Depending on the layout, a better solution would obviously be to provide the width and height using em’s so that the container can expand as font size is increased but this may not always be possible.

    Hope that helps?

  4. Pingback: CSS Image Replacement | CSS Mania

  5. Ron S

    Adding the empty span element does provide the solution for image replacement, but doesn’t it also make for unnecessarily cluttered markup, something that’s not recommended for semantic purposes?

  6. Dave Post author

    Hi Ron,

    Thanks for the comments and it’s a topic that is often touched upon.

    Yes it does introduce an extra span but even some of the CSS guru’s including Eric Meyer himself suggest including extra hooks within the markup which can be used.

    I’m not particularly fond of the idea but when a design requires it, a few extra span’s or div’s are sometimes required and as they don’t actually convey any semantic meaning, it’s not actually misusing semantics.

    As long as semantic markup is actually used correctly, then using a few extra hooks for positioning design elements shouldn’t be too harshly dismissed in my opinion.

  7. RMK

    How about the classic :

    h1 {
    text-indent:-1000em;
    background: url(image.gif);
    height:image-height px.
    }

    Thats the shorter, and doesn’t even need a span tag inside the h1…

  8. Dave Post author

    Hi, Yeah that’s an alternative to the absolute position version above and I agree that it’s probably better as it doesn’t require the span. However, it will still cause problems for users browsing without images enabled so I still prefer the last solution.

  9. Pingback: Make It Up As You Go » Blog Archive » CSS Image Replacement

  10. Jermayn Parker

    Good write up!

    Personally for images that have nice non-web fonts, it would be best to use sIFR instead. Realise sIFR has limits but I think for something like your example, sIFR would be better.

  11. Dave Post author

    Thanks Jermayn, I might have an experiment with it. Obviously the only limitation being that the user must have JavaScript and Flash available although it does have the fall back of text and therefore I don’t see any reason why it wouldn’t be accessible.

    I’ll have a play with the method and post my findings shortly.

  12. leigh

    Nice article, Dave!

    Is there a way of placing images before the text within a class element? For example

    .date{ background:url../images/dateArrow.gif) no-repeat left;
    color: #999999;
    font-size: 11px;}

    In the above example the text overlaps the image.

    Cheers

  13. Dave Post author

    Hi Leigh, do you mean like a bullet-point?

    You should be able to do that by simply applying padding-left: to the class which is equivalent to the width of the image.

    It’s a technique that I use to apply bullet point images to list-items.

    Hope that’s what you were asking?

  14. Jonathan

    hi Dave,

    sorry for the newbie-ish question (i actually am a newbie so its fitting), but how would this change if the top banner and h1 are inside a “#header” div? would i put the and background image inside the header but outside the h1? for some reason i’m struggling to translate it.

    right now i have something like this:

    HD – Please help!

    div#header {
    height:238px;
    background-color:0;
    border-style:dotted;
    border-color:#000000;
    border-width:0px 0px 3px 0px;
    background-image:url(headerPic.png);
    background-position: bottom;
    background-repeat:no-repeat;
    }
    div#header h1 {
    height:80px;
    line-height:80px;
    margin:0;
    padding-left:10px;
    color:black;}

  15. Jonathan

    edit to the above:

    sorry, i tried to paste the html code, and it actually turned it into html lol…

    using “{}” instead of “” the html looks like this

    {div id=”header”}{h1}{acronym title=”Hello Dave”}HD{/acronym} – Please Help!{/h1}{/div}

  16. Dave Post author

    Hi Jonathan,

    You’d need to use the following CSS

    #header h1, #header h1 span {
    width: 256px;
    height: 41px;
    background-image: url(image.gif);
    font-size: 100%;
    }
    #header h1 span {
    display: block;
    position: relative;
    z-index: 1;
    margin-bottom: -41px;
    }
    #header h1 { overflow: hidden; }

    And using your example of HTML you’d also need to introduce an empty span

    {div id=”header”}{span}{/span}{h1}{acronym title=”Hello Dave”}HD{/acronym} – Please Help!{/h1}{/div}

    Hope that makes sense?

  17. Jonathan

    thanks, Dave!

    i think it’s starting to come together, although the h1 text still shows up over the pic when i change the h1 color to gray (since my container’s background color is black).

    one question i have is: in the new css you gave me, there’s no css for #header alone. do i keep what i have for #header{} or just remove it?

    anyway, i don’t mean to turn your kick-ass blog into the “help Jonathan” show (unless you think this could help others)

  18. Dave Post author

    Oops sorry. The span should be inside the h1 tag, sorry about that.

    {div id=”header”}{h1}{span}{/span}{acronym title=”Hello Dave”}HD{/acronym} – Please Help!{/h1}{/div}

    As for the #header style. It depends what you want to do with it. If it’s not doing anything then you could get rid of it and I’d also get rid of the div itself if you can style everything through just the h1 tag.

    I only introduce div’s to wrap around content if they’re required to achieve the layout so if it isn’t actually doing anything then I’d remove it and just style the h1 directly as you should only have a single h1 per page anyway.

  19. Ed

    Why do you need the background image on both the h1 and the span?

    How about using this method for some nav, where does the anchor fit in?

    I almost got it working but the span is sitting in front of the anchor so the hover only works (or is visible) when you turn off the span bg image? Should the span not be behind?

  20. Pingback: Dave Woods - Freelance Web Designer UK » 10 CSS Tips Every Web Developer Should Know

  21. Dave Post author

    Hi Halil,

    Googe doesn’t like hidden text when it is being used to trick the search engines. When you’re using it to replace text with an image that represents the same content then that is absolutely fine.

    The thing to think about is how will users who view your web page with images and css switched off view your page? If the same functionality and content is still available (albeit without the design elements) then you can assume that Google will be fine with your page.

    Hope that helps.