Pure CSS: Better Image Preloading without JavaScript
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:
/* ADD THIS TO CSS */
div#preloaded-images {
position: absolute;
overflow: hidden;
left: -9999px;
top: -9999px;
height: 1px;
width: 1px;
}
<!-- ADD THIS TO XHTML -->
<div id="preloaded-images">
<img src="https://perishablepress.com/image-01.png" width="1" height="1" alt="Image 01" />
<img src="https://perishablepress.com/image-02.png" width="1" height="1" alt="Image 02" />
<img src="https://perishablepress.com/image-03.png" width="1" height="1" alt="Image 03" />
</div>
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.
Footnotes
- 1 Also see Preloading Images with CSS and JavaScript for more information on preloading images.
29 responses to “Pure CSS: Better Image Preloading without JavaScript”
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. :(
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.
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; }
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.
Thanks Jeff, works great for background hovers