CSS Throwdown: Preload Images without JavaScript

Posted on July 22, 2007 in Presentation by

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!!

Related articles

67 Responses

  1. [ Gravatar Icon ] Arjan Eising says:

    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.

  2. [ Gravatar Icon ] Perishable says:

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

  3. [ Gravatar Icon ] Mark says:

    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 each img tag?

  4. [ Gravatar Icon ] Perishable says:

    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!

  5. [ Gravatar Icon ] Lee Allen says:

    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!

  6. [ Gravatar Icon ] Perishable says:

    That makes sense.. Do you happen to know which browsers behave that way? Perhaps I will modify the example..

  7. [ Gravatar Icon ] Lee Allen says:

    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.

  8. [ Gravatar Icon ] Perishable says:

    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!

  9. [ Gravatar Icon ] Marco says:

    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

  10. [ Gravatar Icon ] Nanda says:

    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.

  11. [ Gravatar Icon ] Perishable says:

    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).. ;)

  12. [ Gravatar Icon ] Nanda says:

    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.

  13. [ Gravatar Icon ] Perishable says:

    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?

  14. [ Gravatar Icon ] Nanda says:

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

  15. [ Gravatar Icon ] Perishable says:

    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! :)

  16. [ Gravatar Icon ] Duarte says:

    Hello Perishable.
    Interesting method, but won’t it work if you just use display:none;?

  17. [ Gravatar Icon ] Perishable says:

    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! ;)

  18. [ Gravatar Icon ] Duarte says:

    Glad i could help Perishable, btw congratulations on the great website and articles you provide, i have learned a lot. Thank you.

  19. [ Gravatar Icon ] Vilmer says:

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

  20. [ Gravatar Icon ] Perishable says:

    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.

  21. [ Gravatar Icon ] zjk says:

    the best way i found actually is display:none; of course you should put a .htaccess file with these lines in your media online directory:

    ExpiresActive on
    ExpiresDefault "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…

  22. [ Gravatar Icon ] Perishable says:

    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 of 30 minutes may work fine for, say, images and flash files, but you may want to optimize performance by handling other file types differently.

  23. [ Gravatar Icon ] John says:

    For hiding images it is possible to use z-index

  24. [ Gravatar Icon ] Perishable says:

    Ah yes, good call — thanks for the reminder :)

  25. [ Gravatar Icon ] David Bowman says:

    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.

  26. [ Gravatar Icon ] David Bowman says:

    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.

  27. [ Gravatar Icon ] David Bowman says:

    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.

  28. [ Gravatar Icon ] Perishable says:

    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.

  29. [ Gravatar Icon ] John says:

    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" />

  30. [ Gravatar Icon ] beenee says:

    Worked excellent for my project after Javascript preload methods failed with Safari (Mac).
    Thanks for your efforts!
    b.

  31. [ Gravatar Icon ] Perishable says:

    My pleasure, beenee — thanks for the feedback :)

  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.

  33. [ Gravatar Icon ] Perishable says:

    @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! :)

  34. [ Gravatar Icon ] Sunil Gupta says:

    Hi walrus,

    I am done with the instructions that you mentioned. But nothing is displaying in the browser

  35. [ Gravatar Icon ] evan says:

    Ah, this trick is pretty sneaky, if it works I like it..

  36. [ Gravatar Icon ] Adam says:

    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.

  37. [ Gravatar Icon ] Jeff Starr says:

    @Adam: Thanks for the tips! Adding empty alt attributes to keep the images from displaying in text-only browsers is an excellent idea. Also, is there a reason why one would choose display:none; over visibility: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!

  38. [ Gravatar Icon ] Timothy Stone says:

    Bowman never struck me as a complete ass when I met him. Looks like I was wrong. What’s with that triad?

  39. [ Gravatar Icon ] Mike says:

    @David Bowman

    Man, you couldn’t have been much more of a jerk about it, could you?

  40. [ Gravatar Icon ] Jeff Starr says:

    <aside>I am thinking that this thread has become a prime example of why people should always “think” before they leave a comment..</aside>

  41. [ Gravatar Icon ] Adam says:

    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

  42. [ Gravatar Icon ] Jeff Starr says:

    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! :)

  43. [ Gravatar Icon ] Finn says:

    This is excellent, I use it to load my Virtual Image Tour in WordPress. Thank You…

  44. [ Gravatar Icon ] martin white says:

    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!

  45. [ Gravatar Icon ] Nic says:

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

  46. [ Gravatar Icon ] Jeff Starr says:

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

  47. [ Gravatar Icon ] Nic says:

    Sure but- why not just include the images in the page- where they belong?

  48. [ Gravatar Icon ] Jeff Starr says:

    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.

  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.

  50. [ Gravatar Icon ] Jeff Starr says:

    @Chetter Hummin: I would tend to agree, but until JavaScript is more widely supported than CSS, any JS preloading method is significantly less reliable.

  51. [ Gravatar Icon ] Antony says:

    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

  52. [ Gravatar Icon ] Jeff Starr says:

    @Antony: Wow, you certainly seem knowledgeable about the topic of preloading images. Perhaps you would care to enlighten us with a better technique?

  53. [ Gravatar Icon ] mjcpk says:

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

  54. [ Gravatar Icon ] Antony says:

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

  55. [ Gravatar Icon ] Jeff Starr says:

    @Antony: CSS is used to load images all the time. For example, the background property 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.

  56. [ Gravatar Icon ] ravindra says:

    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

  57. [ Gravatar Icon ] Adam says:

    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.

  58. [ Gravatar Icon ] richard says:

    Great method to use, just wanted to say thanks.

  59. [ Gravatar Icon ] Ken says:

    For some reason, I can’t get this to work in Firefox 3.5.2. Any ideas?

  60. [ Gravatar Icon ] Caderial says:

    I just use this method

    Create a Div tag at the bottom of your page after your footer

    Like so:

    After thats doen create a css rule

    #preloadimg {
    width: 0px;
    height: 0px;
    display: inline;
    background-image: url(images/NAME OF IMAGE HERE);
    background-image: url(images/NAME OF IMAGE HERE);
    background-image: url(images/NAME OF IMAGE HERE);
    etc...
    }

    this seems to work just fine!

  61. [ Gravatar Icon ] Caderial says:

    GAH i made a div tag in my last comment! lol i meant

    Create a Div tag at the bottom of your page after your footer

    Like so: “”

  62. [ Gravatar Icon ] Jeff Starr says:

    @Caderial: I think we get what you’re saying, but you know that method is not going to work. The way your code is written, only the last instance of the background-image property is going to be rendered by the browser. That’s just the way CSS works — in cascading fashion.

    There is a way to do what you’re thinking with CSS3, as I explain here:

    http://perishablepress.com/press/2010/01/04/preload-images-css3/

    For tons more on preloading images, check the list of “Related Posts” at the end of the article.

  63. [ Gravatar Icon ] Norberth says:

    @David Bowman - What contribution did your “wise” words bring to this post? In a related topic you authoritatively attempt to suggest that “triad” (underground society) is a better word than “triage” (which is also an uninspired choice in the context, but that’s an entirely different matter). I’m sorry, but you lose any sort of remaining credibility and pretty much anything you say is mere uninformed opinion. Go and educate yourself before you start another tirade.

  64. [ Gravatar Icon ] Increazon says:

    i will use it now for my buttons on the web site http://apokalipsis-2012.ru/ because it blinking now. check it later if the code really work

  65. [ Gravatar Icon ] Increazon says:

    its looks like it is not working. at least when i mouse over butoon on site, it connecting to server (i can see it using FIREBUG FOR FIREFOX). tHE PATH IS right. so i do not know. hope it will work because i not going to give time to this goal any more. Peace

  66. [ Gravatar Icon ] Morgan says:

    Jeff,

    When a visitor is that rude (yes, I’m talking about David Bowman) there is no need for you to remain polite. You will not lose or offend visitors.

    Tell him to buzz off, and to better himself with something more worthy of his stature. Speak your mind and tell the prick to beat it.

  67. [ Gravatar Icon ] alberto says:

    Hello

    I would like to know how to implement the preload css in my site… I have pasted the css code on the main.css… Now at album_view.htm, what should I do? I have hundreds of images all at a folder in my site… How do I call this folder to preload…

    You can view our present album_viewer here…

    http://regidordigital.com/view-album/3531/confecciones-placi

    Thx very much
    Alberto

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>

Please use basic markup. Wrap code with <code> tags!