As support for CSS improves, pseudo-selectors like :hover, :active and :focus will become more widely used. Already :hover is in use on many sites to provide rollover states to buttons, as on this site (the menu bar). The other pseudo selectors will, in time, give far more opportunities for the use of rollover images.
One potential problem with image rollovers, though, is that in order for an image to be displayed, it must be downloaded. Consequently, for rollovers to work smoothly and quickly, all the necessary images must be already available on the user's PC. Otherwise, the rollovers will behave badly, like in this example using large images.
Until recently, rollover effects were achieved through use of JavaScript, and as a result, a plethora of solutions to the preloading image problem in JavaScript are available. However, using JavaScript to preload images, though not a bad idea when using JavaScript to control rollovers, becomes less bright when it is CSS that's controlling them. A user could very easily (and this is becoming more common) have a CSS-capable browser without JavaScript support or with JavaScript turned off.
So there's a clear need for a way to use CSS to preload images or find another way to avoid the problem. Which gives us two relatively simple solutions to our problem.
The first solution is to create a single background image for your element that actually contains both the rollover and non-rollover images, and then position is using the background-position CSS property. Instead of changing the image when the mouse moves over the element, you can simply change the background-position to reveal the previously hidden rollover image. There's a more detailed explanation of this technique over at WellStyled.com.
The other option available to you is to trick the browser into downloading the image before it is required for the rollover. This can be done by applying the image as a background to an element, and then hiding it using the background-position property. The image will then be downloaded but will not be displayed. Then, when the rollover is activated, it will operate smoothly and instantly.
First, you need to select an element that doesn't currently have a background image. If so select an element that does have a background image, you will either end up not preloading the image you are after, or you will prevent the element's normal background displaying. Neither is ideal.
Once you have picked an element to use for this purpose, you need to add the background image. The following CSS can be applied to the element and will place the background image outside the viewable area of the image:
background-image: url("rollover_image.png");
background-repeat: no-repeat;
background-position: -1000px -1000px;
Your rollover image will then be loaded when the page itself is initially loaded, along with the other images. When a rollover is then activated, the image will already be available to the browser and the effect will be instant.

57 Comments
Good idea ... but what would you do for several images? Assign each image as backgrounds for various page elements? This might get a bit cumbersome. Not had a chance to think about this but could you use display: none or something like it?
#1, Clive Walker, United Kingdom, 23 December 2004. Reply to this.
Using display:none; should mean the image is downloaded, but presents an accessibility issue.
If you were using a lot of images, this would potentially be unweildy. However, in most cases only one or two images would be needed.
#2, Dave Child, United Kingdom, 23 December 2004. Reply to this.
A pretty clever approach. It looks like a good alternative to the Wellstyled approach. Thanks.
#3, Bill Slawski, United States, 24 December 2004. Reply to this.
But then comes IE...
IE doesn't see the :hover selector when it comes to anything else but <a> tags...
Any known solution for that?
And about using more than one background image in a page - you can make one image with several background images on it, and play with the position the same way.
#4, Zohar, France, 6 May 2005. Reply to this.
I been using a DIV tag with a display:none as attribute, and there inside dumped the image-overs I needed, with quite crossbrowser success so far and making acorrect user experience...
#5, waldito, Spain, 11 May 2005. Reply to this.
Re the last comment - unfortunately some browsers do not load images that are inside a display:none block (or that have display:none on the img tag itself). I've hit this problem with Moz 1.2.1, apparently it also affects Opera and some versions of IE.
See http://www.quirksmode.org/css/displayimg.html
#6, Jamm!n, United Kingdom, 27 May 2005. Reply to this.
Is there any advantage in using background-image as suggested here, rather than just putting the images in a block which is then positioned off-screen?
div.hidden {
position: absolute;
top: -4000px;
}
Or does this have the same problem as display:none in some browsers? (Damn those optimisations...)
#7, Jamm!n, United Kingdom, 27 May 2005. Reply to this.
Just adding an empty div with a particular background-image should work. Try adding this div to the end of the page instead of the beginning, that way, hover preloads won't adversely affect page display time. Since it's zero-height being an empty div, it won't affect the layout no matter where you put it. Since it doesn't have display:none, the browsers don't have a cue to mindlessly neglect loading it.
/* Plain and simple. */
.preload
{
background-image:url(hover.png);
}
<body>
...
<div class=preload></div>
</body>
#8, David Beal, United States, 13 June 2005. Reply to this.
load them using a iframe that is hidden by having a smaller z-index than a blank white div in front.
#9, Anonymous, United States, 11 November 2005. Reply to this.
Don't use iframes. Just use a div and assign the div the background-image which you want to see on hover. Then ensure your link sits within the div. Set the background-image for the a tag to the 'normal' state, and the hover state a:hover { display:none;}. This way the background for the a tag will be hidden on rollover, revealing the background loaded on the div enclosing it.
#10, Anonymous, United Kingdom, 22 November 2005. Reply to this.
I agree the best way to do it is using div instead frames.
#11, Guanajuato City, Mexico, 14 January 2006. Reply to this.
Here's a great way to do it.
#preload { height: 0; overflow: hidden; }
<div id="preload"><img src="..." /><img ... ></div>
It doesn't affect flow, it doesn't show, it works for Opera, Firefox, and IE on a PC that I've tested. The downside is that there is HTML markup. But this is far less hassle than working with Javascript and overcomes the CSS On/Javascript Off problem.
Replies: #54.
#12, Joel Watson, United States, 2 February 2006. Reply to this.
It may be that images aren't downloaded because - according to the spec - a box isn't generated when display: none; is set.
However, visibility: hidden; still creates a box and affects the flow of the document, so I would think that all browsers would download the background, regardless of the box's visibility.
Of course, this is just supposition. If anyone has tried this method - and can verify or dismiss this suggestion - please do.
#13, Robert Buelke, United States, 16 February 2006. Reply to this.
Good idea, but if I want to preload more than 1 image?, anybody think that is better to use javascript?
#14, Carlos MagaƱa, Mexico, 18 February 2006. Reply to this.
RE:#14 -
If you want to preload multiple images, you could just create a class with the CSS to hide & preload the image, while keeping the image-specific CSS in another class/id.
Alternatively, you could probably create a wrapper div with the preload CSS, and then put the images within it. The images will load, and assuming they're relatively positioned, they should remain hidden offscreen along with the parent div.
(Or, if you opt to hide the parent div with visibility:hidden instead of positioning itabsolutely and offscreen, they should inherit that. Same effect, slightly different method.)
Sure, it creates extra code, but so would any other method. Regardless of how you do it with CSS, you won't have to worry about javascript being turned off on the client-side.
#15, Robert Buelke, United States, 20 February 2006. Reply to this.
To Joel Watson - thanks for your idea. It have used it on my site and it seems the most simple solution. Cheers!
#16, Guy Dorey, United Kingdom, 13 April 2006. Reply to this.
Is there any downside to:
#preloadDefaultImages {
width: 0px;
height: 0px;
display: inline;
background-image: url(~/App_Themes/Basic/images/fill_over.gif);
background-image: url(~/App_Themes/Basic/images/login_over.gif);
background-image: url(~/App_Themes/Basic/images/review_over.gif);
background-image: url(~/App_Themes/Basic/images/shred_over.gif);
}
<body>
<div id="preloadDefaultImages"></div>
#17, Dave sadler, United States, 23 April 2006. Reply to this.
I like that method Dave! Works for me. Thanks.
#18, Shesha Marvin, United States, 10 July 2006. Reply to this.
Great tips man! I *knew* there was a way to do this, but couldn't find the answers. Now I have! Thanks Dave!
#19, felipe, Canada, 20 July 2006. Reply to this.
That seems to work well for opera, firefox, and ie, Dave. However, Netscape doesnt seem to honor the philosophy (at least in my first tests). It appears that netscape does some prliminary rendering of the html first and decides it doesnt need to request the preloaded images - i would guess because of its dimensions.
#20, pete, Canada, 28 July 2006. Reply to this.
So, I meant to say, I guess that brings us back to the author's original idea which works nicely in all 4 browsers.
BTW - does the author/webmaster of this page know that these addedbytes pages render with no content in Netscape (7.1) ?
#21, pete, Canada, 28 July 2006. Reply to this.
you can simply hide the div containing the images...
.preloader {
position:absolute;
top:-1000px;
left:-1000px;
}
seemed to
http://www.addedbytes.com/css/preloading-images-with-css/comments/#comment12
<div class="preloader"><img src="blabla.jpg"></div>
#22, LeoCavallini, Brazil, 15 August 2006. Reply to this.
Good tips people!
I have gone for Joel Watson's tip.
Top stuff!
#23, Trystan Hughes, United Kingdom, 29 September 2006. Reply to this.
This is infact good solution for Opera and Mozilla based browsers but not for IE. Internet Explorer dosent support image preloading with CSS.
#24, M Aamir Maniar, India, 7 October 2006. Reply to this.
visibility: hidden;
position: absolute;
Works perfectly for me, no dodgy hacks.
#25, Lewis, United Kingdom, 24 October 2006. Reply to this.
All what you proposed does not work with IE 6 properly, any idea?
#26, Sameh Fakoua, Lebanon, 17 November 2006. Reply to this.
I just found tried this and it worked for me:
#nav li a:hover{
background: url(/images/nav-item-up.jpg) no-repeat;
_cursor: hand;
_background: none; filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='/images/nav-item-up.jpg',sizingMethod='crop');
color: #ffff00;
}
IE doesn't load the filter on every roll-over, no flicker, but I needed to add the cursor: hand to make it seem like a regular link.
#27, r2b232, United States, 26 November 2006. Reply to this.
I used #22's tip (LeoCavallini) and it works wonderful even with multiple images. I also checked it with the latest IE, Mozilla and Opera with no problems.
I still use javascript for my roll overs but #22s tip combines with it wonderfully. Thanks
#28, Knoll House Interforum, United Kingdom, 19 December 2006. Reply to this.
I experience problems too with IE7 and FF2.
So I developed my own script which can be found here:
http://www.haan.net/test/preloader1.php
Please feel free to copy, paste and adjust to your needs.
#29, HAAN.net javascript, Netherlands, 19 January 2007. Reply to this.
Thanks for the trick. I hated that "small" time you must wait for the image to load.
#30, PET, Romania, 5 March 2007. Reply to this.
I came up with the following solution for may site
.loadbg {
display:none;
height: 0px;
margin: 0px 0px 0px 0px;
padding: 0px 0px 0px 0px;}
<img src="images/hmleftbg.gif" class="loadbg">
#31, Shawn, Unknown, 23 March 2007. Reply to this.
i came up with the same idea for preload in css , there is so many tags with no backgrounds that it is quiet easy to insert.
Very useful for roll overs in menu with hidden text .
img tags can as well hold css preload in their backgrounds :).
For the display:none; option , i might remenber that netscape will not preload the background , following strictly the rule display:none; it will not care about it at all.
beside the height:0; overflow:hidden; and z-index:-1 (for opera) works fine too to hide somethings , but it could become extra tags ... where using empty backgrounds makes it easier :)
great site !
GC
#32, gcyrillus, France, 4 April 2007. Reply to this.
Thanks for sharing this idea, I was looking for a css preload technique for my image rollover menus. I appreciate the help!
#33, Carrousel Yacht, United States, 25 July 2007. Reply to this.
This method works most of the time but when you are working with multiple layers or two different images in IE you will sometimes get flicker. If you load a wrapper with the same image (in my case I used a table td around a nested div identically sized) you can fool IE. Basically it is smoke and mirrors. In the gap between the time it takes the image to change you just show a repeat of the first image.
If you are real sharp I guess you can code in a browser detection so that Firefox doesn't pay for IE's slow transitions.
Thanks Dave! I have enjoyed your site again and again! Just like my JD!
#34, LCTPAdmin, United States, 11 September 2007. Reply to this.
#34 touched on the issue of IE flicker. In the first technique (the Pixy method: one image with both states, revealed by background position), IE can flicker b/c that browser pings the server for the image again (even though it shouldn't).
The same fix should work. Apply the same background image, in hover state position, to the element's parent. In that instant while the image flickers on hovering the element, the parent's copy of the image rollover will be there to save the day. This works best with simpler designs, of course.
For example:
<p><a href="#">hover me</a>
/* background image */
a, a:link, a:visited {background:url(image.gif) 0 0 no-repeat;}
a:hover {background-position:0 -50px;} /* image moved up whatever distance needed */
/* background image in rollover position, applied to parent element */
p {background:url(image.gif) 0 -50px no-repeat;}
Also, a few earlier comments noted another problem with that fact that IE doesn't apply the :hover pseudo-class to anything else but <a> tags. There is a behavior file out there that fixes this - search for "csshover.htc", problem solved!
#35, luispunchy, Germany, 7 January 2008. Reply to this.
thanks!! nice one
#36, Jad, United Kingdom, 18 April 2008. Reply to this.
This is absolutely brilliant. I have been searching for a non-javascript solution to do this for ages. Cannot thank you enough. ILove[redacted].com!
#37, Adaptiv Media, United Kingdom, 4 May 2008. Reply to this.
joel watson #preload { height: 0; overflow: hidden; }
<div id="preload"><img src="layout1.png" /><img ... ></div> what to put inside <img ...>???
#38, itruscan, Switzerland, 9 June 2008. Reply to this.
Here is what I do. If this helps anyone, terrific... I'll go buy myself a snickers bar and feel all fuzzy inside. If not... I'll sink into a deep depression and rock back and forth in the darkest corner of my office muttering "Mad Word" by Tears for Fears...
In my CSS:
#preloader {
position:absolute;
top:-1000px;
height:100px;
width:100px;
overflow:hidden;
}
Then at the very top of my page under the body tag:
<div id="preloader">
<img src="preload-image-1.gif" height="10" width="10" border="0" />
<img src="preload-image-2.gif" height="10" width="10" border="0" />
<img src="preload-image-3.gif" height="10" width="10" border="0" />
etc...
</div>
This will not be visible on your pages, and *should* take care of any browsers that do not render images if a "0" size is given to them or if they are "hidden".
I actually use this to eliminate the delay that browsers seem to have loading CSS background images but I can't see how it wouldn't work for rollover images as well.
I have tested this using FF and Safari on Mac as well as IE6 and IE7 on Windows. I have not tested it in the lesser used browsers because, truth be told, shooting myself in the face right this second with a 12 gauge shot gun would be a more joyous alternative to the self-torture I'd subject myself too if I tried to please the logic/rendering engines of every single browser. In the words of the late, great Bob Marley: "You can't fool all the people all the time..."
Cheers!
#39, Dameian, Unknown, 26 June 2008. Reply to this.
A co-worker of mine suggested using CSS sprites technique (http://alistapart.com/articles/sprites/), since the bg image is loaded when you load the pre-hover state of the element, all you would need to do is specify background positioning for the css hover declaration.
#40, George, United States, 2 October 2008. Reply to this.
I have been using CSS display:none effectively (.hiddenPic {display:none;}, but I'm not testing with any older browsers, which is a worry.
I just tried #39 (Dameian) and it works fine for everything EXCEPT Chrome, which puts the little 10x10 icons of the images in the lower left corner, obviously not processing the -1000 positions.
I then added the .hiddenPic class to the img lines, and now even Chrome is handling it correctly, as expected since it is the new kid on the block.
Thanks, all. Great site.
Joseph
#41, Joseph, Unknown, 26 January 2009. Reply to this.
I am facing a totally opposite issue :) Is there a way to "prevent" loading of images until some action. I have a div which has 100+ images in it. I want to show the div only on some action by the user. Even though the div has display:none set, the images gets preloaded. Is there a way to solve this ?
#42, Rakesh, India, 5 February 2009. Reply to this.
well after reading all this I ended using an iframe for our company site http://www.teamquest-inc.com.ph , this is because I need to preload more than ten image and a swf/flash file that will be used in other page of my site, so in the home page i insert iframe in a div position off screen. this works for our company site.
#43, danreb, Philippines, 3 March 2009. Reply to this.
A technique that I use drastically reduces the number of HTTP requests required for image preloading in addition to eliminating the need for any additional code to preload images. I've written a brief post on it here: http://www.bjornenki.com/blog/preload-roller-images-without-css-javascript
#44, Bjorn Enki, Los Angeles, CA, 22 May 2009. Reply to this.
After reading all this and *most* of the comments, I tried just adding div wrappers around my list items, and adding the rollover background to them with an id tag.
My challenge was that I'm building a list of categories (for my portfolio) as a navigation for the portfolio categories. But I'm using my text in the images, so I need separate backgrounds for each category, being 9 total.
So what I did and seemed to work out well was to wrap each <li> in <div> tags, and give each a separate id, such as:
<div id="preload_print_ro">...then target each one with just a CSS rule for the background image.
Now, instant rollovers, no flicker!
#45, Joel G, Pennsylvania, US, 22 June 2009. Reply to this.
Thanks for the tips. I solved it by adding the images to background image of divs inside a div. It worked and was cross browser. I had 3 images for a menu bar and the file sizes where relatively small, anything bigger i would of used JavaScript.
#46, Chris Ward, United Kingdom, 23 September 2009. Reply to this.
I an fascinated by the whole idea of pre-loading images in My web pages but what I am confused about is once the images are pre loaded how do I call them for viewing in the web page?
I am guessing this is really a stupid question but I would not be wasting your time if I already knew than answer.
Okay so lets say I down pre loaded the images in and make them invisible.
Now in the location on the page where I am gong to need it to appear, I just add the img tag like normal???
Another thing I am confused about is,,, calling the "src" of the imgae after it has been "cashed"
I mean initially I would call the image from the image folder on My server with a something like <img src="images/nameofimage.jpg />
but once it is cashed in My browser do i still call it with the same url???
Thank you in advance for your time and patience with those of us who are still struggling with this stuff...
Leo LeMat
leo_lemat@yahoo.com
#47, Leo LeMat, Unknown, 30 September 2009. Reply to this.
@Leo LeMat
I suppose you are a bit on the wrong side regarding this topic.
What people here are talking about is "preloading" images for later use. This means on other pages of your website. So, if you have a gallery.html on your homepage, just "preload" the images included while your visitor is reading "home.html" or some other page.
As soon as he visits gallery.html the browser will have a look at your cache directory. All images that are already there don't have to be requested and therefore downloading the page seems to be much faster.
If you are talking about "preloading" images for a page you are actually looking at, this doesn't make sense. You have to download all included images either way or the other.
If you want to change the background-image of an element for any reason, I advice you to use the sprite technique. Glue several images together and change the backgroundposition with css (http://alistapart.com/articles/sprites/). This will prevent the dreaded flicker effect.
The sprite technique is also great for designs that require loads of images to be downloaded, because instead of handling countelss requests, you are asking just for one single image and later you use css to position it.
Something you can do, is to give your visitor an alternative while he is waiting for the download to complete.
Have a look at: http://dinolatoga.com/2009/04/26/how-to-create-a-visual-image-preloader-using-jquery/ for a possible solution (javascript).
Regards,
pepebe at gmx de
#48, pepebe, Germany, 2 October 2009. Reply to this.
To Leo LeMat:
It is not necessary to change the way you refer to an image after you have preloaded it. The browser "remembers" that it has cached (say) "../images/img04.png" and the next time it is referred to in the CSS file (again as "../images/img04.png"), the browser will get it from the cache rather than download it from the server, thereby sidestepping the download delay and annoying flicker in IE.
To pepebe:
Sorry, but I think it's actually you that has missed the point. If you read Dave Child's piece at the top of the page, he is specifically writing about preloading images so that there is no flicker of :hover images (and similar) on the same page. It still counts as pre-loading because the image will in all probablility be cached before the viewer hovers and clicks on a menu item.
Preloading images so that they are cached by IE and therefore available more quickly on a new page such as a gallery is probably better implemented with javascript because there is likely to be a number of images and one may not have sufficient CSS elements without a background image that one can use to load images covertly.
To Dave Child:
I found this technique worked brilliantly for me - just three lines in the CSS file to overcome this problem is amazing - the best solutions are usually the simplest - so many thanks for publishing this elegant workaround.
I suggest that the probable reason for the success of this solution is that IE does not seem to cache :hover images (and other dynamically chosen images) at all, but presenting the image first as a background image forces the browser to cache it. For the record I have found this still to be a problem in IE8. Exactly what they are smoking at Redmond is anyone's guess...
#49, Steve K, United Kingdom, 21 November 2009. Reply to this.
My solution is very similar, but is used for all images on my entire site. I have a class called "image-preload" where I set several background-image properties on it. I have a div with this class in my layout file (so its loaded on every page) and then the above styling effects. works great for my site!
#50, Sean Coleman, 24 June 2010. Reply to this.
your "Ads BY Google" and "Translate" options appear above your fancy bar across the top ("Jump to:" etc.).
#51, visitor, United States of America, 20 July 2010. Reply to this.
Yeah, this totally worked for me too! Plus, since Google is counting speed in their algo now, it's pretty darn helpful.
Nice work. :)
#52, Chad Lawson, USA, 28 November 2010. Reply to this.
Wow! I was using a related technique I saw on some other site and didn't work as quickly as I expected (instead of moving the background outside the viewable area, it was just setting background back to none afterwards). Your example works much quicker.
Thank you very much!
#53, Mihai Marica, Romania, 3 December 2010. Reply to this.
#12 worked brilliantly for me - I was able to preload all of my images by adding the first part to the css and the second part to the html on my index/home page. All other pages responded instantly to the rollover because of the homepage preload. I assume this means that if someone lands on a different page, it won't be preloaded unless I put that html on every page - but I'm far too lazy to add it to all pages :p
#54, John, New Zealand, 21 March 2011. Reply to this.
a suggestion if you'd like to implement some progress indicator:
var c1 = new Image();
c1.src = 'images/alea.png';
c1.onload = function(){
updateLoadProgress(1);
}
#55, bt, norway, 30 May 2011. Reply to this.
I realize that this post was made in 2004, but it helped me today, almost seven years later. thanks a lot!
#56, Ross, 6 July 2011. Reply to this.
Agreed! I just come up with the same solution, Dave.
#57, jani anderson, 21 October 2011. Reply to this.