changing html images on hover/a quick css trick

published on:
December 17, 2008
comments

Changing an image on hover in css is a piece of cake. It's a common technique that has been used for a long time and received a number of improvements over the years (think css sprites). Changing an html image on hover is a little harder and when I ran into this very problem a week or so ago it had me stumped for about 30 seconds. More than enough to dedicate an article on a selection of solutions to refresh people's memory.

what we want to accomplish

Hovers on html images are not too common, as most images in html are purely content images and are not related to the actual design. One important exception is the site logo, which is best placed in html instead of css. It's common practice to put a home link on the site logo and when hovered, it's nice to see a hover state indication, subtle as it might be. To summarize what it is we want to do exactly:

  • Place an image in the html source
  • Change the look of the image when hovered
  • Stay clear of any javascript and solve the problem using css only
  • The image has to show up on print at all times, as seen on the page.

The final condition is the reason why we can't rely on css images only, and even though sprites can be used, we have to make sure only the base image shows up on print.

the first solution: sprites

a {display:block; width:100px; height:50px; overflow:hidden;} a:hover img {margin-left:-100px;} /* ie6 needs his fix*/ a:hover {zoom:1;}

Our first solution makes use of sprites. This means that both versions of the image are created in the same file. In this case, the image is 100px wide, so the hover state of the image is placed 100px to the right of the base image. We give the link the dimensions of the image and add overflow:hidden to hide the hover state. When we hover, we simply pull the image to the left and up comes the hover state. IE6 is not very cooperative and needs a little fix, a simple zoom:1 does the trick though.

A pretty easy trick, which shows up well on print too (as the overflow:hidden is applied), only when disabling the css altogether does this technique fail, as both states of the image will show up next to each other. Apart from that, the technique has good browser support with only IE6 being a little annoying (what else is new).

check out the example on the demo page

the second solution: separate images

a {display:block; width:100px; height:50px; background:url("logo-2.gif") left top no-repeat;} a:hover img {position:absolute; left:-999em; top:-999em;} /* ie6 needs his fix*/ a:hover {zoom:1;}

The second solution is a little dirtier, but shows up well even with css disabled. The idea is to make a separate image for the hover state and to place it behind the actual image in css. When the link is hovered, we simply position the base image away and what remains is the hover state of the image defined in css. A simple trick, but effective, with no lag as the css image is defined on the link and is loaded when the page is renderen for the first time. Again, IE6 needs a little push to make it work, adding a simple zoom:1 is all it takes.

Apart from the little IE6 tweak this is a pretty handy solution, though it does require you to load two separate images. If you're aiming for speed, this might not be your choice of preference.

check out the example on the demo page

a third alternative: transparent images

a {display:block; width:100px; height:50px; background:#fff; overflow:hidden;} a:hover {border:0px solid red; background:#00FF21;}

The third solution is the easiest to do in css but requires some graphical preparation and only works when doing color effects. Still, it's a nice technique that could use some more attention. The trick is to make part of your image transparent. You then define a base background color which you overwrite on hover. You can use gifs for simple images or pngs for more interesting masks. More information can be found in my article on png masks.

A very effective method, though hard to accomplish with png masks as ie6 has bad png support. Apart from that, also limited in effect as it can only be used to influence the color of your logo.

check out the example on the demo page

a final variation: css transparency

To finish off the article there's a final variation on the color theme described in the third alternative. Rather than use a transparent html image it's also possible to use css transparency to get a nice highlight effect. Here too you can do simple highlights using background colors or try more complex masks by using images. More information on this technique can be found on the SocialGeek blog.

rounding up

Maybe (read: probably) I missed some solutions, but these were the ones that sprung to mind immediately. They all have their pros and cons but between the three of them you should have more than enough options to accomplish what you want. Nothing too difficult or complex, but it gives your site that little extra.

Comments

Thomas Byttebier

comment number
date
December 17, 2008 11:04

Nice overview. I have gotten so used to the sprites technique that I use it nearly everywhere now. But as you point out that may not be the most stylish way of doing things.

SocialGeek

comment number
date
December 17, 2008 11:15

I think the sprites technique is only workable if the image is defined in the css file. Considering html images, I'm much more in favor of the latter solutions provided in this article for the sole reason of the full sprite showing up when style sheets are disabled or unavailable (as pointed out in the article).

John Faulds

comment number
date
December 24, 2008 05:32

I always use the 2nd solution as it's the one that will work best in most situations.

Niels Matthijs

comment number
date
December 24, 2008 10:00

Well, the second solution is my preferred one too, will be using it in my new blog design.

As for the first solution, I think there's an alternative way to handle it by clipping certain parts of the image in css (clip property). Ran into it the other day, have no idea how well it is supported cross-browser though.

广告笔

comment number
date
December 27, 2008 09:11

i am used to the first one.Maybe the bad one,but i used to it.

Dave

comment number
date
December 29, 2009 16:31

I've got to ask: what is the picture that illustrates this article?

Niels Matthijs

comment number
date
December 29, 2009 16:43

Hah!

It's actually a hovercraft (largest one in the world I believe). The craft of hovering etc ... :)

Wout de Zeeuw

comment number
date
March 01, 2009 21:24

Ellooo,

Tried solution with the 2 images, but unfortunately if you do that in IE 7, and you try using applying it to 2 different buttons with 2 css id's, then IE 7 will use the first hover image on the second id... argh! The sprite image approach works better. In firefox there's a little wierdness though, it does something different if you do or , isn't that wierd???

Wout

djlebarron

comment number
date
April 02, 2009 17:07

I couldn't come up with a simple way of putting my lettering on the "non-hovered" image in the second solution. As it's presented, I would have to have my text as part of the actual image. I also would have to have an ID for each link and provide seperate background images and seperate base images for each link in each link's unique CSS (this also relates to Ellooo's comment). Too much muck.

I simply switched the "blank" background images via CSS a:hover, and then placed my text (once) in the link. If a user comes to the site with CSS disabled, the text link still shows. Anyone going to my site with CSS disabled is going to have a hard time making heads or tails of it anyway, and I suspect that's the case with most modern sites. I'll provide for the JS disabled, but having to provide for the CSS disabled may be a bit extreme and counterproductive. Like I said, the text links will still be there for the CSS disabled.

Here's the code with five links...

<html>
<head>
<style type="text/css">
a {
display:block;
color: white;
font: 12px verdana, geneva, arial, sans-serif;
text-align: center;
padding-top: 5px;
text-decoration: none;
width:120px;
height:25px;
background:url("menu.gif") left top no-repeat;
}
a:hover {
color: black;
background:url("menu2.gif") left top no-repeat;
}
</style>
</head>
<body>
<a href="index.htm">Contact</a>
<a href="form_listing.htm">Listing</a>
<a href="advertise.htm">Advertise</a>
<a href="update.htm">Update</a>
<a href="contact.htm">Contact</a>
</body>
</html>

Luke Day

comment number
date
April 06, 2009 12:48

@djlebarron,

That works great, but its better if you have two images in one and move the background image, this ensures that there is no flicker or wait when the hover state is loaded.

Brian K

comment number
date
July 13, 2009 23:03

Used the 2nd solution. I'm not a frontend person by trade (Ruby guy actually), but was able to use this elegant method very quickly and easily. I showed it to one of our designers and he really liked the implementation. I forwarded this post to him for a CSS talk he's giving later today. We're going to take a look at using the 2nd solution over sprites in certain areas of our site.

Thank you.

ambilibmenon

comment number
date
February 19, 2010 12:47

my cell of the table contains 3 (text) links to diffrent files.as i move over on the cell,my background color of that particular cell is being changed. but i want the color of all the 3 text also to change along with the background change. i am successful in changing the cell background. but not able to change all the 3 text colors at the same time. please help me out of this problem if u r willing. my email-id: ambilibmenon@yahoo.co.in

Gary

comment number
date
March 06, 2010 03:34

beautiful site you should be proud

elamonii

comment number
date
May 06, 2010 11:26

thanks a lot. its really helpful :)

sick

comment number
date
June 09, 2010 02:38

The second solution worked great for me. I'm running a source theme from Elegant Designs and it fits the dimensions great. I've padded each cell more than normal to give it that new millenia feel.

Mahesh

comment number
date
July 03, 2010 12:21

How to Change the particular color of the image in css

Bill

comment number
date
October 25, 2010 06:40

Very, very helpful. Thank you.

allan

comment number
date
November 10, 2010 20:44

The second option does what I want, however I seem to loose the href link that the first image is attached to - any ideas?

Compton

comment number
date
December 14, 2010 00:27

Would I be able to create these as #Name then reference the ID with in the <a id=Name Etc...

Page

comment number
date
December 15, 2010 14:18

Great thing is with a little bit more code you can make it animate in. CSS3 transitions are great.

-webkit-transition: opacity 1s ease-in-out; -moz-transition: opacity 1s ease-in-out; -o-transition: opacity 1s ease-in-out; transition: opacity 1s ease-in-out;

John

comment number
date
April 10, 2011 10:37

I agree with Page, we should try to look at using css3 and html properties... not to do it for the sake of doing it but to try out new things.

jakes

comment number
date
July 11, 2011 23:46

I’ve been searching around the net and haven’t really come up with an answer. So I’m asking if maybe you know if it’s possible to use “inline CSS Sprites” with my employer’s logo for an email signature. Just a simple mouse over effect from grey to color with link (possibly without use of “background”. The closest thing I found thus far is http://css-tricks.com/3427-css-sprites-with-inline-images/ but they are using embedded css. Email compatibility for browsers email and app mail like to strip embedded css.

Any help would be much appreciated thanks.

fe

comment number
date
August 17, 2011 21:03

thanks!

Brian K.

comment number
date
November 22, 2011 20:38

Thanks. This is what I was searching for and I think I'm going to use the 2. version which seems OK for me. First one is better if there is a speed problem wince the second one is working after both image loaded

czmarci

comment number
date
May 20, 2012 20:08

First solution is the best :) thank you.

* required fields

Leave your data
Leave a comment