Plugin Sale! Save 15% on pro plugins with discount code: FALL2020
Web Dev + WordPress + Security

Pure CSS: Better Image Preloading without JavaScript

[ Preload Images with CSS ] After reading my previous article on preloading images without JavaScript1, Nanda pointed out that adding extra markup to preload images is not the best approach, especially where Web Standards are concerned. Mobile devices, for example, may experience problems when dealing with the following preloading technique:

div#preloaded-images {
   position: absolute;
   overflow: hidden;
   left: -9999px; 
   top: -9999px;
   height: 1px;
   width: 1px;

<div id="preloaded-images">
   <img src="" width="1" height="1" alt="Image 01" />
   <img src="" width="1" height="1" alt="Image 02" />
   <img src="" width="1" height="1" alt="Image 03" />

Thus, as Nanda suggests, it is better to preload images using only CSS. Using the CSS background property, we can preload images via existing <div>s, <span>s, or other elements in the (X)HTML markup.

Let’s say you have three images (e.g., image_01.png, image_02.png, and image_03.png) that you would like to preload using this method. First, examine your markup for three identifiable <div>s (or other elements) that may be used as CSS hooks for the preloaded images. For example, looking at the source code of the current page, I would choose the following three divisions:

  • <div id="wrap">...
  • <div id="jump">...
  • <div id="header">...

Then, to implement the preload, I would add the following code to my site’s CSS file:

div#wrap {
	background: url(image_01.png) no-repeat -9999px -9999px;
div#jump {
	background: url(image_02.png) no-repeat -9999px -9999px;
div#header {
	background: url(image_03.png) no-repeat -9999px -9999px;

Here, we are preloading each image into its own unique <div> and then preventing its display by positioning it to the far left of the browser window. If the preloading elements are empty with no discernible height or width, hiding the preloaded images off-screen should not be necessary because they will not be displayed. Even so, it is probably a good idea to relocate them just to be safe.

Of course, once you have implemented this code to preload your images, they will be immediately available (depending on size) for display in your document as needed. Simply refer to them as normal using whatever CSS code that you would normally use. For example, once these images have preloaded, I could employ the following :hover technique with minimal presentational delay:

a#first:hover {
	background: url(image_01.png) no-repeat 50% 50%;
a#second:hover {
	background: url(image_02.png) no-repeat 50% 50%;
a#third:hover {
	background: url(image_03.png) no-repeat 50% 50%;

According to my tests, this technique works well in any browser (including IE 6) that supports the CSS background property. Best of all, this preloading method is entirely unobtrusive, requiring no presentational code and degrading gracefully in non-supportive browsers.


Jeff Starr
About the Author
Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
BBQ Pro: The fastest firewall to protect your WordPress.

29 responses to “Pure CSS: Better Image Preloading without JavaScript”

  1. And what if you’d like to preload the images for a slideshow, that will be started as soon as all of the images are loaded? (Or at least the next one.) How can it be checked? I do not know the solution, but I guess that it won’t work in this “CSS-way”. So maybe it is not the best solution. :(

  2. Jeff Starr
    Jeff Starr 2010/11/04 8:16 am

    Hi Swirlsky, you’re probably better off using JavaScript or even Flash for a decent slideshow experience. I have also read that in HTML5, you can use next and previous-image meta-tags in the header to tell the browser which images to fetch next. Totally unsure about the functionality and support for that, but it may also be something worth checking out.

  3. Does anyone have an aversion to the following technique?

    #imagePreloader { display:none; background:url(images/image1.jpg); background:url(images/image2.jpg); background:url(images/image3.jpg); background:url(images/image4.jpg); background:url(images/image5.jpg); background:none; }

  4. Jani, I’m no expert, but that method seems to depend on the behavior of the user agent. IOW, the browser must (1) load multiple, repeated backgrounds and not the first or last only, and (2) further override the url()s with ‘none’. While it may work, it would require testing and I’m guessing isn’t defined behavior in the standard.

    I was thinking, though, that it might be more elegant to use classes, e.g.:

    div#preload { display: none; }
    div#preload.1 { background-image: url(...) }
    .2 { background-image: url(...) }
    .3 { background-image: url(...) }

    IIRC, the ID will override the class, being more important, but the multiple classes should all get applied. I haven’t tested this, just a thought.

  5. Thanks Jeff, works great for background hovers

Comments are closed for this post. Something to add? Let me know.
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
WP Themes In Depth: Deep dive into WP theme development.
Watching. Waiting. Praying.
Got all of my free WordPress plugins updated for imminent WP 5.6 in early December. Pro plugin updates currently in the works.
7G Firewall now integrated into BBQ Firewall (free version). Pro version soon ;)
macOS Big Sur update complete. So far no crazy issues. Except TextEdit, which is completely screwed up and unusable. Replaced with free BBEdit.
Got so sick of macOS’ annoying “red dot” that I had to remove System Prefs from the dock. Come on Apple you can do better.
Beginning development of an Nginx version of 7G Firewall.
Happy Birthday to Perishable Press, celebrating 15 years online! :)
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.