Inline image replacement

May 22, 2008 at 9:56pm.

This entry is about Web design

9 comments.

You may have noticed the very last line on this website, crediting the cms and host I am using. It turned out to be much more difficult to make that effect work than I was expecting, so I thought I would explain my code for anyone else who needs to do something similar.

The easiest solution would have been to use an <img /> tag in the flow of the text. There were two problems with this: The first is my philosophical issue with using an image tag when semantically I want text. The second problem is making the image change color when the user hovers their mouse over it, like all the other links on the page. Of course I could have set up and onMouseOver script that would switch the images, but I didn’t like that, either. The classic image-replacement trick of saving both the normal and the “hot” images in one file and then adjusting the background-image-position in css is so much faster and more elegant.

So I started looking at image replacement techniques. Unfortunately, all the standard methods require the replaced image to be a block-level element. This obviously won’t work in my case, since it would put each image on a separate line. With a bit of experimentation, I found a method that allows me to keep the replaced image as an inline element, keeps the link and tooltip active, and even lets me underline the image on mouseover, just like a normal link.

First try

I am going to be working with this xHTML for my first experiments:

<p>This is a line of text with a <a href=”#” class=“replaced” id=“butterfly”>butterfly</a> in the middle.</p>

I want to replace the word butterfly with an image of a butterfly: Butterfly image

There is a CSS position property called “inline-block” that would seem to combine the necessary qualities of both “inline” positioning—keeping the replaced image inside the flow of text—and “block” positioning—creating a defined space that an image can be placed in. And it does, except that it is not part of the CSS specification and Firefox doesn’t support it. However, Firefox does support their own implementation, called “-moz-inline-box”. So combining those with the standard image-replacement code, we get:


.replaced {
display: inline-block;
display: -moz-inline-box;
background-repeat: no-repeat;
background-position: 0 0;
overflow: hidden;
text-indent: -9999px;
} #butterfly {
width: 22px;
height: 18px;
background: url(butterfly.png) no-repeat;
}

Which gives us:

 

This is a line of text with a butterfly in the middle.

That’s close—the image shows up in the middle of the sentence, as desired, but in Firefox and IE the image is still overlaid with text.

Second Try

Adding two new rules to the stylesheet will make it work in Firefox:

.replaced {
display: inline-block;
display: -moz-inline-box;
background-repeat: no-repeat;
background-position: 0 0;
overflow: hidden;
text-indent: -9999px;
font-size: 0;
vertical-align: text-top;
}

 

This is a line of text with a butterfly in the middle.

But Internet Explorer, the bad boy of the browser world, only shows a little glob at the top of where the image should be. Fortunately, my default solution to all IE bugs works in this case. Adding zoom: 1 gives the image “layout” and causes it to re-appear. (Incidentally, both display: inline-block and setting the dimensions should trigger hasLayout, but for some reason they don’t in this case.) Zoom is a Microsoft proprietary extension to CSS, so it won’t validate, but neither will display: -moz-inline-box. If that bothers you, move them to alternate style sheets…I’m not too worried about it.

Underlining on hover

On my site, like many others, an line appears under links when you place your mouse over them. Since I wanted to directly replace the text in my sentence with an image, it would make sense that it would also have the underline. If you have a rule in your stylesheet for a:hover already, the image-replaced link will inherit it automatically, but the line will be directly under the image rather than a few pixels lower like it would be with normal text. So I add some padding to the bottom on hover. I also adjust the background position to show the second, hightlighted, image that is below the normal one.

#butterfly:hover {
background-position: 0 -18px;
border-bottom: 1px solid;
padding: 0 0 2px;
}

 

This is a line of text with a butterfly in the middle.

Looks great, right? Except if you are using Firefox, which refuses to add the padding to the bottom. As reported by Firebug, Firefox actually decreases the height of the element to cancel out the added padding. Weird. The only solution I have found requires adding an extra <span>, which I generally avoid. I moved a number of CSS rules to the new span and added three extra rules. The line height of the span is set to the height of the image, to prevent it from showing part of the highlighted image below. Also, IE7 no longer shows the “hand” cursor, so I added a rule to fix that. Lastly, I added -3 pixels of margin to the bottom to offset the padding and border.

The final code is:

<p>This is a line of text with a <a href=”#” class=“replaced” id=“butterfly”><span>butterfly</span></a> in the middle.</p>

.replaced {
display: inline-block;
display: -moz-inline-stack;
background-repeat: no-repeat;
background-position: 0 0;
vertical-align: text-top;
zoom: 1;
} .replaced span {
display: block;
overflow: hidden;
text-indent: -9999px;
line-height: 18px;
cursor: pointer;
} #butterfly {
width: 22px;
background: url(butterfly.png) no-repeat;
} #butterfly:hover {
background-position: 0 -18px;
border-bottom: 1px solid;
padding-bottom: 2px;
margin-bottom: -3px;
}

And the final result is:

This is a line of text with a butterfly in the middle.

Comments:

David King gravatar

David King on August 2, 2008 at 11:48am#1

Nice work! Thanks for the code!

Farshad Ali gravatar

Farshad Ali on August 19, 2008 at 5:48pm#2

Very nice tutorial. I like your website design too.. thanks for the tutorial and good luck.

EliVZ gravatar

EliVZ on August 19, 2008 at 9:19pm#3

Glad I could help!

Peter gravatar

Peter on September 8, 2008 at 6:53pm#4

Exactly what I was looking for, but is there any way to get this working in IE6?  Challenge!

EliVZ gravatar

EliVZ on September 8, 2008 at 11:08pm#5

@Peter: Good catch! The technique actually does work in IE6, or would if I had remembered to put a href in the final link. IE6 has trouble with :hover on anything other than a proper link. I have updated the examples.

yussi ariefiyono gravatar

yussi ariefiyono on December 18, 2008 at 12:30pm#6

great stuff! thank!

Anika gravatar

Anika on February 20, 2009 at 6:05pm#7

Very helpful article, thanks!
There’s one error, though. You wrote ‘“inline-block” [...] is not part of the CSS specification’. That’s not true, it is not part of CSS2, but of CSS2.1: http://www.w3.org/TR/CSS21/visuren.html#display-prop

James gravatar

James on April 3, 2009 at 4:31pm#8

Hi, just a heads up.  In IE8, the third butterfly works properly but the last one does not show the blue one.  In all examples, hover makes it underline, which jobs the following text downward.

Christian Sisson gravatar

Christian Sisson on December 17, 2010 at 9:29am#9

Thank you 1.000.000 times!!!

Got something to say?