changing html images on hover

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.