main content, site navigation, search

Preload :hover images in CSS

Now that the majority of CSS blogosphere is accessing the Internet with some kind of broadband connection, we kind of forget about Dial-up users. We do all kind of trickery to make our images lighter and faster to download, but even though, sometimes the first time visitor gets the flicker when hovering a link with a background image.

Most of the time, pixy’s workaround with a single image, which is positioned accordingly will do, but sometimes for whatever reason, we need completely separate images. Preloading background images with CSS is so cheap trick, that I sometimes laugh at myself how could I forget about it.

a { background: url(image_hover.gif); }
a:link { background: url(image_default.gif); }
a:hover,
a:focus { background: url(image_hover.gif); }

Update

The code example was rather generic, now it’s altered for those who are in a hurry : ) and have no time to read through valuable discussion in the comments.

27 shouts to “Preload :hover images in CSS”

  1. Rob Mientjes
    001—2005.06.22.16:12

    It’s mind-numbingly simple. Thanks for reminding me :)

  2. Clay
    002—2005.06.22.19:03

    That works? Huh. I’ve been using the sprite technique since before it showed up on ALA, but I’ll keep this in mind. Of course, I don’t have any style graphics on my own site, but hey…

  3. Justin P
    003—2005.06.22.19:27

    Very cool, I was just thinking about this the other day. Thanks for providing the help, that’s just what I was looking for.

  4. Crano
    004—2005.06.23.22:07

    Oh yeah! Totally forgot about that! I usually do the positioning one image thing.

  5. Peter Flaschner
    005—2005.06.24.02:33

    I’ve been using an extra div (I know, boo hiss) with the id “preload”. I position this off stage, and ba-da-bing.

    This method is much cleaner though. Thanks.

  6. Jared Christensen
    006—2005.06.24.14:53

    How does this work? I am not following.

  7. Sage
    007—2005.06.27.06:56

    I think it works because the browser first sees the “a” selector, and so will load the hover image, since “a” covers all anchor states.

    You then “undo” that with the a:link selector, which states the non-hover image.

    a:hover and a:focus are there just to make sure that the browser knows to load the hover image for those states.

  8. Leo
    008—2005.06.28.14:22

    Hmph… nice idea. I’ve also been using the “position hover images off screen” technique described by Peter, but your suggestion is very simple and cleaner. Nobody aware of any instabilities with this method?

    Thanks.

  9. michael
    009—2005.06.29.00:16

    the problem with pixies rollovers is that he uses fixed width (or height) buttons, which don’t scale very good (to say the least). But why should your method be better for modem/isdn users ? you have to download all images, be it in one merged (pixie) or be it in two seperate. i would be suprised if the difference in filesize would be that much. prob. a few bytes. the real advantage of pixies method is that the rollover-state is there when you *need* it. Your method seems to do the job as well, besides it allows us to use *wallpaper*-buttons, that scale much better. so 2:1 for you ;-)

    No matter which one you choose,the css will get messed up again with tricks, and workarounds.

  10. trovster
    010—2005.06.29.20:41

    Hey, that’s pretty nifty. I’m guessing it works how Sage described it, but a confirmation would be nice!

    I’ll still stick to the Pixy method for my rollovers. I tend to merge images together anyway, hopefully saving size in the process but definitely saving trips to the server and thus speeding up rendering time.

  11. marko
    011—2005.06.30.16:00

    @trovster:

    “I’m guessing it works how Sage described it, but a confirmation would be nice!”

    Consider Sage’s description confirmed : )

  12. Eric
    012—2005.07.03.22:55

    Hi! I’m still a bit new to using CSS style sheets. I still don’t understand how to use your tip here, but it sounds like it would be the best thing to avoiding adding more html to my pages to preload the images. I want to use it for my navigation buttons. An example of some of my nav button CSS code can be found at http://www.esbuys.com on any page of the site (all using the same CSS file). How do I incorporate your tip into it? Thank you!

  13. Matt Keogh
    013—2005.07.07.18:38

    Maybe I am being a bit slow today but I could not get this to work.

    I think it was (either todays slowness) or the order of the links and the a:visited selector.

    I tried this:
    a{background: url(img_hover.gif); }
    a:link, a:visited { background: url(img_default.gif); }
    a:hover { background: url(/img_hover.gif); }

    This loads the background image for all links states, turns it back to the top image for the up state and visited links and then lastly overrides this with hover.

  14. Eric
    014—2005.07.08.01:40

    Well, I don’t know if it’s correct or not, but you are missing the comma after your first line:

    a{background: url(img_hover.gif); },

    At least you’re missing it if you’re trying to use the example from Marko… also, you’re missing the a:focus part…

  15. Matt Keogh
    015—2005.07.08.10:52

    Eric, thanks for looking into this for me but I meant to leave that comment out. You can’t have a comma after the declaration only after the selector.

    I re-checked my method looking at my temporary internet files folder and the rollover image does not appear in there until after I have rolled over (it does not get preloaded).

    I have re-tried the above method and it shows the rollover image without rolling over. It is as though the a:link does nothing. I am going to look into this further.

    Does anyone have a link to a working example so I can work out what I am doing wrong and confirm this works?

    On a side note - the a:focus does not work for IE but a:active does.

  16. Matt Keogh
    016—2005.07.08.11:13

    I suppose another technique would be set the background inside a different element such as a list item and then use the background position to move this away.

    No as elagant as the above method though…

  17. Matt Keogh
    017—2005.07.08.11:48

    argh! Just found out about the IE Image flicker problem! Is there no end to this madness!?

    It appears that the bg image does load into the cache but then expires or something after a short while and the page reloads from the server rather than the cache.

    great.

  18. Tim
    018—2005.08.06.11:08

    Great idea, saved me a load of trouble.

    I think the :hover class needs to be defined last though.

    This setup works for me:
    a{background: url(hoverimage.gif) 30px 40% no-repeat;}
    a:link,a:visited{background: url(normalimage.gif) 30px 40% no-repeat;}
    a:hover{background: url(hoverimage.gif) 30px 40% no-repeat;}

  19. jehiah
    019—2005.09.19.05:21

    Ok, I’m not a huge fan of preloading images in css, but I could see it’s uses. If any of you are looking for something in Javascript I have a clean implementation up on my site http://jehiah.com/archive/simple-swap

  20. feaverish
    020—2005.10.12.17:55

    Wow, I just can’t get this to work. I’m using unique IDs for each of the links; could this be the problem? My code looks something like this:
    #home {background: url(image-hover.jpg)}
    #home:link {background: url(image.jpg)}
    #home:visited {background: url(image.jpg)}
    #home:hover {background: url(image-hover.jpg)}

    The hover image does not preload for me at all; I get a flicker while the hover image loads for the first time in every browser (though it seems like sometimes it preloads the hover image in Safari; don’t ask me why).

    What am I doing wrong? (Oh and you can see the site?and flickering?in action at http://www.lisadejohn.com.)

  21. feaverish
    021—2005.10.12.22:23

    Update: I still couldn’t get this technique to work, but I was able to get the same effect by applying the hover image to the background of the container element (in my case the list item element) and the default, non-hover image to the contained link states (except :hover, obviously). The only drawback (besides a ton of IDs) is that a visitor with a slow connection will see the hover image load before the default image. In my case it wasn’t a big deal, and it actually looks kind of cool.

    Zeldman details the procedure here (2nd item).

  22. Matthew
    022—2005.10.25.19:09

    This seems like such a cool and simple way of dealing with preloading backgrounds, and I understand how it is supposed to work - but I couldn’t get it to work in any browser I tried. Has ANYONE had success with this? And could you point out an example of it working?

    Back to javascript preloading for now…

  23. Mike
    023—2005.11.07.23:52

    I ran into the same problem where I was using list elements for a menu, and all menu items had its own image / hover-image pair. The solutions I’d seen I didn’t like or didn’t work so I came up with a solution I’m happy with and which seems to work always to get rid of the flicker. The solution I came up with is to simply add the hover state image within the HREF and give the image a visibility:hidden style (I’m using style=”preLoad” and then have the CSS in a seperate file). I feel this is the ‘cleanest’ way to do it without too much overhead.

    For an example have a look at the source code of this site.

    Just my 2 cents, hope it helps.
    Mike.

  24. Cuzog
    024—2005.11.21.02:25

    Just thought I’d let the people having problems know that the reason it doesn’t work as written here in IE is that IE goes with the “a” background rather than the “a:link” background when the link is already visited. The corrected code that also works in IE is this:

    a { background: url(image_hover.gif); }
    a:link,
    a:visited { background: url(image_default.gif); }
    a:hover,
    a:focus { background: url(image_hover.gif); }

  25. moo
    025—2006.01.03.06:24

    are you sure is’s working? i’ve tested under xpsp2 lastest patched with httpwatch, the hover image is NOT preloaded

  26. Lucas Recalde
    026—2006.01.03.21:46

    Thanks a lot. I apply your solution but i have to do some changes to work in IE. I’ve use a shim image for each menu. The result is XHTML 1.0 compliant and works very well. You can check it at http://www.doliaku.com.ar (is the main menu).
    PS: sorry for my english language, i hope you understand what i am trying to say!

  27. Martin Bour
    027—2006.11.19.16:01

    I landed on your site looking for a way to preload background images for links. I could not get your solution to work. This is what I was doing:
    a.about {
    background: url(images/menu/about_ON.gif) 50% 50% no-repeat;
    }
    a:link.about {
    background: url(image/menu/about.gif) 50% 50% no-repeat;
    }
    a:hover.about, a:focus.about {
    background: url(images/menu/about_ON.gif) 50% 50% no-repeat;
    }

    I found another solution which seemed to work for me. I ended up creating a div on the page with class imageLoader which looked like this:
    .imageLoader {
    background: url(images/menu/about_ON.gif);
    background: url(images/menu/products_ON.gif);
    background: url(images/menu/downloads_ON.gif);
    background: url(images/menu/messages_ON.gif);
    background: url(images/menu/news_ON.gif);
    background: url(images/menu/contact_ON.gif);
    visibility: hidden;
    }

    then I had my link backgrounds set up normally with a, and a:hover classes.

    it is working on mac (Safari and Netscape), but have not tested all browsers.

Comments are closed.

main content, site navigation, search