If you are reading this, please get modern browser.
skip to main content | skip to main navigation | skip to secondary content

Preload :hover images in CSS

~ 22nd June 2005. · 12:42 CET · permanent link · printer friendly ~

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 Comments

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

  2. 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. 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. Oh yeah! Totally forgot about that! I usually do the positioning one image thing.

  5. 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. How does this work? I am not following.

  7. 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. 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. 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. 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. @trovster:

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

    Consider Sage’s description confirmed : )

  12. 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. 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. 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. 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. 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. 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. 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. 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. 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 www.lisadejohn.com.)

  21. 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. 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. 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. 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. are you sure is’s working? i’ve tested under xpsp2 lastest patched with httpwatch, the hover image is NOT preloaded

  26. 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 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. 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.

Sorry, the comment form is closed at this time, but if you have anything to say, please send me a message.

* Please keep in mind that this is a personal web site and it does not reflect the position or opinion of my respective employers, organizations or partners.

Typetester – compare screen type Supported by Veer.

What is this?

A web log of Marko Dugonjić, web professional from Croatia. Topics covered:

Translate this site

German, Spanish, Italian, French or Japanese (via).

See you there!

Feel like buying a book?

Try with maratz.com aStore

Worth visiting

top of the page | skip to main content | skip to main navigation | skip to secondary content