CSS Throwdown: Preload Images without JavaScript
by Jeff Starr on Sunday, July 22, 2007 – 60 Responses
Clean, easy, effective. You don’t need no stinking JavaScript to preload your images. Nope. Try some tasty CSS and (X)HTML instead! Here’s how.. (only two steps!)
Step 1 — Place this in your CSS file:
div#preloaded-images {
position: absolute;
overflow: hidden;
left: -9999px;
top: -9999px;
height: 1px;
width: 1px;
}
Step 2 — Place this at the bottom of your (X)HTML document:
<div id="preloaded-images">
<img src="http://perishablepress.com/image-01.png" width="1" height="1" alt="" />
<img src="http://perishablepress.com/image-02.png" width="1" height="1" alt="" />
<img src="http://perishablepress.com/image-03.png" width="1" height="1" alt="" />
</div>
..and that’s a wrap! All images are preloaded and ready for calling as you please. Completely valid, standards-compliant image preloading via CSS and (X)HTML!!
Focused on clean code and quality content, Perishable Press is the online home of Jeff Starr, author, artist, designer, developer, and all-around swell guy. 





60 Responses
Add a comment
Arjan Eising – #1
This will not work as you expect…
The images are loaded, but that is because they are in the XHTML code.
The CSS does not apply any background to the
div-element, because you ‘overwrite’ the background with an empty one.Perishable – #2
Yes, thank you. I am updating the article with something that actually works ;)
I think the updated code works fine. I tested it in Firefox, Opera, and IE7. Let me know if something goes bonkers..
Mark – #3
With this method, a user without CSS or CSS disabled is going to see a series of images at the bottom of the page. Why not do a
width="0"/height="0"on eachimgtag?Perishable – #4
Good call, Mark! Anything to enhance usability/accessibility is always welcome. I have updated the (X)HTML code with your suggestions. Thank you for helping to improve the method!
Lee Allen – #5
Some browsers will not load an image with a width of 0px and height of 0px set as they realise it is not showing. It needs to be at least 1 x 1 px!
Perishable – #6
That makes sense.. Do you happen to know which browsers behave that way? Perhaps I will modify the example..
Lee Allen – #7
As far as i know its the more recent browsers IE6+ and Firefox 2.0+. I have read about this issue before but have taken it into account rather than testing it.
Perishable – #8
Okay, I went ahead and changed the code in the post to specify 1×1 image sizes. I think the logic is sound, and until I find time to test and research it myself, I would rather error on the side of caution. Thanks for the heads up!
Marco – #9
I don’t know if I think this is absolutely stupid (which it actually is), but on the other hand it’s really genious.
I like fresh ideas like this one, keep it up!
Greetings,
Marco
Nanda – #10
Its better to assign background images with css (e.g. with url(’image.png’) to either empty xhtml elements, or existing ones that don’t need a background image. You can do it this way without adding any extra html code. adding html to a site for this purpose should not be encouraged as it does not follow the semantic standards, it will create problems in certain mobile browsers for instance.
Perishable – #11
All excellent points, Nanda. Thank you for sharing them with us! Do you have any prime examples of which (X)HTML elements would best serve this technique? I can think of a few (e.g.,
<br />,<hr />, etc.) with which the background images wouldn’t be visible, but perhaps I am overlooking the obvious (again).. ;)Nanda – #12
In the past I have just used empty s, unless they have something inside them they will not have any height/width attributes and so will not show they background images. You can also use any existing elements in your code and simply move the background image off screen by setting something like “background: url(image.png) no-repeat left -10000 -10000)”. This way is probably best as it involves no extra code in your xhtml, so keeping the rule of no presentational code.
Perishable – #13
Hi Nanda, thanks for continuing the conversation ;) Reading your comment, I am assuming that WordPress ate the “
<div>” placed directly before the “s” in your first sentence. If so, I would argue that an empty<div>(or any other element) qualifies as “non-semantic” markup, which should also be avoided within a strictly web-standards context. Admittedly, an empty element is an improvement over one that is filled with images, however, I think that your second, CSS-only method serves as a far better solution overall. Do you know if there are any browsers for which the CSS-only technique does not work?Nanda – #14
The CSS only method is certainly better, it will work in any browser that supports background images, so far I’ve had no problems in any modern browsers (including IE 6).
Perishable – #15
Excellent — thanks for sharing this method with us. I am going to experiment a bit and perhaps check a few crusty browsers for support. After spending some quality time with the technique, I will update this article and post an “new and improved” version! Thanks again for your help! :)
Duarte – #16
Hello Perishable.
Interesting method, but won’t it work if you just use
display:none;?Perishable – #17
Hi Duarte,
Yes, I think this method will work when using
display:none;. I have yet to test it, but logically it makes sense. Such images are still loaded by the browser, yet not displayed to the user. Thus, the images will have been “preloaded”. A very elegant improvement indeed, Duarte — thank you! ;)Duarte – #18
Glad i could help Perishable, btw congratulations on the great website and articles you provide, i have learned a lot. Thank you.
Vilmer – #19
Thank you for this very useful post. I make ‘360 degrees virtual tours’ and had the problem that visitors had to wait for a more than 1 megabyte image to load after a change of scene. Now I have implemented your code, with the display:none command, without using an external css file, and the images load in a few seconds now!
See the source of the link to one of my tours above.
Thanx! And pls let me know if it works on all browsers, since I only have iexplorer 7 and the latest firefox..
Perishable – #20
Sounds great, Vilmer — thanks for the feedback concerning your very practical application of the CSS-preloading technique. As for the cross-compatibility, I have not tested every browser on earth, but can definitely reassure you that the image-preloading method will work for a vast majority of your visitors. I think just about any modern browser (e.g., Firefox, Opera, IE7+, Safari, etc.) supports it.
zjk – #21
the best way i found actually is
display:none;of course you should put a .htaccessfile with these lines in your media online directory:ExpiresActive onExpiresDefault "access plus 30 minutes"(ref:http://httpd.apache.org/docs/2.0/mod/mod_expires.html)
now i try to cleanup some, the whole animation loading as long as it sometimes look a bit and rough ^^
anyway with an infinite and unpredictable number of image to preload, i suggest to improve a bit this functionnality… (i’m actually trying to find how to catch an event like “all images are preload,
display:block;the whole thing”)if you have ideas…
Perishable – #22
Careful with that htaccess, zjk! Setting default content expiration is great, so long as you specify expiration times for specific file types (e.g.,
.js,.css,.html, etc.) as needed. Depending on your needs, a default expiration value of30 minutesmay work fine for, say, images and flash files, but you may want to optimize performance by handling other file types differently.John – #23
For hiding images it is possible to use
z-indexPerishable – #24
Ah yes, good call — thanks for the reminder :)
David Bowman – #25
pretty crappy to post a bunch of code that you didn’t even test before you spewed it out onto the internets.
why do you have to position the DIV off the screen? it’s already hidden with CSS. it’s never, ever going to be visible unless CSS is disabled or unsupported.
David Bowman – #26
yeah, i just tested it out… all you have to do is hide the DIV that contains the preloaded images using “display: none” and the problem is solved. it doesn’t require positioning, overflow, height/width properties. just one line of CSS. your solution is major overkill.
David Bowman – #27
just read through the comments above.
“A very elegant improvement indeed, Duarte!”
why don’t you just delete this page or take down your bloated code? you just didn’t know enough about CSS to realize that what you posted to being with was totally ridiculous.
Perishable – #28
Hi David, thanks for the feedback. I appreciate your efforts to improve this technique. Rest assured, I am no expert in CSS, but do enjoy helping others with discoveries, tricks, and other bits of information. At the time of its original posting, this article represented my understanding of a way to preload images without using JavaScript. Since then, several people have helped improve the technique and contributed to the conversation in a positive way. I apologize for any frustration at my apparent lack of CSS knowledge. One of the reasons I enjoy sharing my ideas is to watch as they are used and improved upon by others.
John – #29
2 David: good idea !
CSS:
img.preload { display: none; }HTML:
<img src="http://perishablepress.com/image-01.png" alt="" class="preload" /><img src="http://perishablepress.com/image-02.png" alt="" class="preload" />beenee – #30
Worked excellent for my project after Javascript preload methods failed with Safari (Mac).
Thanks for your efforts!
b.
Perishable – #31
My pleasure, beenee — thanks for the feedback :)
SneakyWho_am_i – #32
For me, display:none broke it. I don’t think that I would use this technique in production for semantic reasons, but I have been doing it in testing and as long as I DON’T display:none it, it works fine. I can’t tell you which browser didn’t like it being invisible that way though. May have been Firefox 3.
Some simple tests though; use the “preloaded” images (on an empty cache of course) as cursors on hover, or reveal them on activation of a link (in a background tab).
Related: We’ve found that if you display:none; a swf movie that you’ve embedded with x/html, that movie becomes totally silent. Never thought to check whether it actually loads or not, but to hide flash you have to move it offscreen.
I’m not a fan of people who hide anything that makes a horrible noise on the internet though, I have my own music playing when I’m working, thank you very much, jerks (not you, them)
Anyway, I HOPE that I’ve not talked a lot of rubbish just now.
Perishable – #33
@SneakyWho_am_i: absolutely not a lot of rubbish there, but some interesting information that will inevitably lead to more testing and experimentation. I am currently baffled as to why Flash movies would behave that way when preloaded using
display:none;— sounds like a bug to me! Thanks for the information! :)Sunil Gupta – #34
Hi walrus,
I am done with the instructions that you mentioned. But nothing is displaying in the browser
evan – #35
Ah, this trick is pretty sneaky, if it works I like it..
Adam – #36
It should be noted that if you are preloading images in CSS at the bottom of your page, that you set the ALT tag as blank alt=”" so that they don’t appear for anyone using text only or screen reader browsers. Otherwise, at the bottom of their page they’re going to see a massive list of images “Image 1″, “Image 2″ that are completely irrelevant.
If they are for preloading, you don’t want them to appear as part of the website.
Also… instead of “display:none” … try “visibility:hidden”.
If the container is 1px by 1px it doesn’t really matter if it takes up physical space.
Jeff Starr – #37
@Adam: Thanks for the tips! Adding empty
altattributes to keep the images from displaying in text-only browsers is an excellent idea. Also, is there a reason why one would choosedisplay:none;overvisibility:hidden;? If I remember correctly,visibility:hidden;prevents the content from showing, but doesn’t remove other properties such as padding, margins, and widths.. if so, then I think I get what you are saying in that last sentence. Thanks again!Timothy Stone – #38
Bowman never struck me as a complete ass when I met him. Looks like I was wrong. What’s with that triad?
Mike – #39
@David Bowman
Man, you couldn’t have been much more of a jerk about it, could you?
Jeff Starr – #40
<aside>I am thinking that this thread has become a prime example of why people should always “think” before they leave a comment..</aside>Adam – #41
Me again, thought I’d add another suggesting for people regarding preloading images (with the assumtion they are for hover effects).
You could use the “sprite” method (something I’ve been playing with).
For example, if you have a bunch of buttons and they all have a hover effect you simply join the two images together to make one image.
So lets say you have a button that is 100px by 50px.
Join it with the other graphic to make one image that would become 200px x 50px. (Buttons are side by side in the graphic).
Then.. in your CSS you do this:
============================
a {display:block;width:100px;height:50px;background-image:url('mysprite.gif');background-repeat:no-repeat;background-position:0px 0px;}a:hover {background-position: -100px 0px;}So basically all you are doing is repositioning the background image so that the hover part is now visible.
It also means, you dont have any additional stuff to do to preload anything because the graphic has been loaded fully.
Hope that helps someone :)
Adam
Jeff Starr – #42
Definitely cool, Adam! Thank you so much for sharing this technique with the readers here at Perishable Press. It is very much appreciated. Happy New Year! :)
Finn – #43
This is excellent, I use it to load my Virtual Image Tour in WordPress. Thank You…
martin white – #44
Well done Adam and thank you!
I’ve been making a navigation list with 4 states for each link - the sprite method has reduced my link images from 28 to 7 - nice!
This is by far the slickest method which doesn’t require any surplus markup.
Keepin’ it nice n tidy!
Nic – #45
Just curious, what applications does this have? The only thing I can think is for CSS image rollovers- in which case sprites are typically the best solution (and leaves no extraneous markup).
Jeff Starr – #46
@Nic: I have seen image-preloading techniques used for slideshows, shopping carts, portfolios, and for design-related images in general. Anywhere you are using lots of images and want them to appear with no delay, preloading is a helpful tool.
Nic – #47
Sure but- why not just include the images in the page- where they belong?
Jeff Starr – #48
Are you asking about why designers use preloading methods? If so, it has to do with ensuring that graphics are displayed instantaneously, without any delay otherwise caused by preloading. This is difficult to achieve by simply placing the images “in the page.” I guess I’m not sure what you are driving at here, but let me know if you are still confused about it.
Chetter Hummin – #49
The drawback is, because the images are technically part of the page, the browser is going to load them… that’s why it’s a preload, right? But it will load them WITH the rest of the page. A Javascript preload usually triggers just after the page is rendered, while the user is looking at the finished page. This will trigger DURING the layout. So it will slow down the initial page load and rendering.
I’m sticking with the Javascript. Besides, it’s like 5 lines of code - that’s LESS than this method.
Jeff Starr – #50
@Chetter Hummin: I would tend to agree, but until JavaScript is more widely supported than CSS, any JS preloading method is significantly less reliable.
Antony – #51
the method is completely wrong. I think you’re forgetting the most basic of CSS/xHTML/JS. HTML is for Presentation, CSS is for Styling and Javascript is for the Behavior.
You’re using CSS to simulate behavior to a page which is wrong. Imagine a screen reader or a search engine trying to crawl this web page…. get it? How would you explain this DIV on a search engine? Also the empty ALTs are so lame! This is so Web -2…
cheers
Jeff Starr – #52
@Antony: Wow, you certainly seem knowledgeable about the topic of preloading images. Perhaps you would care to enlighten us with a better technique?
mjcpk – #53
@Nic - The images only belong IN the page if they are content. If they are just there to make things pretty then they should be referenced in the external CSS file.
The golden rule is if you turn CSS off does the absence of the image detract from the meaning of the page? If so put the image in the HTML, if not put it in CSS.
@Antony - HTML is for content. It is for the bits that have meaning. CSS is for the styling of the content. Therefore CSS is the for PRESENTATION of the HTML.
@martin white - whilst you’re at it you could combine all the images into one big sprite and go from 28 images to 1.
@everyone - There are lots of reasons to avoid using javascript. Not least of all because that JS should be in a separate file and therefore requires another HTTP connection to fetch it. If you’re already using a CSS file then it doesn’t require another HTTP connection to preload some images with it.
Antony – #54
@Jeff Starr: no I don’t. I’m just using a simple JS preloader when I have situations like rollover navigation buttons etc. Your technique is very clever thought it can’t be used because of the nature of xHTML and CSS.
@mjcpk: we’re saying the same thing but you must understand that this method is trying to create ACTIONS and BEHAVIOR on a web page using CSS which is semantically wrong. There is a good reason why JS is there and I can sacrifice one more file request for the shake of image preloading. I’m always using CSS Sprites when it comes to re-usable graphics on my pages so one more file request is not a big deal. For me it matters more the content to have meaning and Web Standards to work on my pages.
Jeff Starr – #55
@Antony: CSS is used to load images all the time. For example, the
backgroundproperty is commonly used for loading and displaying various types of background images. Is this considered behavior? Are you saying that using CSS to load a background image does not qualify as behavior but that using CSS to load a gallery image somehow does qualify as behavior? How can you define loading images as behavior based on how the images are used on the page? Or are you defining CSS image loading as behavior based on whether the images are displayed or not? If so, what about sprites? Sprites are not always seen, so is it semantically correct to use CSS for sprites? CSS is used not only to load and display the sprites, but also to change the position of the sprite images based on certain actions. So does this count as behavior? Maybe we should stop using CSS to display all images because some of them are applied via “behavioral” CSS while others are not? Please help us to understand how to apply semantically sound Web Standards to the proper handling of images via CSS.ravindra – #56
Nice post! I like it….The images are loaded, but that is because they are in the XHTML code. it also very light and it download very fast . great
Adam – #57
Hmmm, well this seems to have got a little out of hand :)
@Antony - Its nice to see you understand the accessibility side of things with the empty images without “alt” tags. Did you know that if an image doesn’t contain an alt tag it doesn’t appear on a screenreader? Alt tags are there to provide an Alternative description for the image in the case where it is important to make sure the person browsing the website can still understand the message of the page IF the image is part of that message. Preloaded images don’t need alt tags. The original image can contain it. Lets think of those people using screenreaders for a moment… I personally wouldnt want to know there was an image call “preloaded image” on the page because it means nothing to my experience of reading the page I’m on. So lets not stick them in places they aren’t needed without thinking about the logic of why we put it there.
Anyway, a-side, Im with @mjcpk on this and personally believe the CSS approach is better because.. well, it works without Javascript, less HTTP requests and the total image sizes are lower (combining 2 images to one is smaller because there arent two image headers involved and it combines pallets).
Thinking of accessibility again, lets not just assume that everyone has Javascript. In the instance of it being disabled, the CSS hover effect is still going to work. CSS has something called “hover” Antony. Its an effect and its been around a long time. Its purpose is to create an “effect” when people do things on the page. It’s so we don’t have to rely on Javascript all the time to do very basic procedures such as mouseover effects. I personally don’t want to have to apply a function to every link on the page OR produce a recursive onload event to apply a hover effect to my elements. That’s why CSS has these little things to help us apply a global effect quickly to the page. What you are saying is that CSS should not have the :hover effect anymore because its producing an action and a behaviour. (looks puzzled).
Oh, and another thing.. preloaded images still load at almost the same time as the page content. Did you know that the header scripts run when the XHTML code is finished loading and NOT the images? This means that whilst images are loading in the body, your javascript is already running too and loading those additional preloaded images. It doesn’t wait until all images in the BODY are finished before it fires.
Finally.. the “nature” of CSS and XHTML is what exactly? The purpose of XHTML is to produce a globally aligned programming structure that we can follow to help us produce sites that work better on a myriad of browsers and devices. CSS is the thing that then paints it.
Javascript should only be used to enhance the experience for those that can use it, the website should NEVER, in any circumstance, rely on it as its primary source of functioning. There should always be a fallback. So the less we use Javascript, the better.
richard – #58
Great method to use, just wanted to say thanks.
Ken – #59
For some reason, I can’t get this to work in Firefox 3.5.2. Any ideas?
Trackbacks / Pingbacks