Super Plugin Sale! Your Choice: BOGO or 30% Off »
Web Dev + WordPress + Security

Better Image Caching with CSS

[ CSS3 ] I have written previously on the fine art of preloading images without JavaScript using only CSS. These caching techniques have evolved in terms of effectiveness and accuracy, but may be improved further to allow for greater cross-browser functionality. In this post, I share a “CSS-only” preloading method that works better under a broader set of conditions.

Previous image-preloading techniques target all browsers, devices, and media types. Unfortunately, certain browsers do not load images that are hidden directly (via the <img> element) or indirectly (e.g., via the parent <div> element) using either display:none; or visibility:hidden;. Further problematic is the potential unintentional display of images on pages when presented via specifically designed print stylesheet.

To get around these limitations, we begin by segregating our strategy to target different media types. For example, for web pages featuring both screen and print stylesheets, we treat each separately by writing this:

@media screen {}
@media print {}

Then, to ensure that the images are preloaded in all browsers, we need to avoid the use of either display:none; or visibility:hidden; in the method. Rather than risking non-caching by hiding or preventing the display of images that need preloaded, we ensure their display and position them far outside of the screen. To do this, we enclose all images that need cached within some specifically identified division like so:

<div id="preloader">
	<img src="http://domain.tld/path/images/01.png" width="1" height="1" />
	<img src="http://domain.tld/path/images/02.png" width="1" height="1" />
	<img src="http://domain.tld/path/images/03.png" width="1" height="1" />
	<img src="http://domain.tld/path/images/04.png" width="1" height="1" />
	<img src="http://domain.tld/path/images/05.png" width="1" height="1" />
	<img src="http://domain.tld/path/images/06.png" width="1" height="1" />
	<img src="http://domain.tld/path/images/07.png" width="1" height="1" />

Then, with that markup in place, we flesh out the previous media directives with the following CSS:

@media screen {
	div#preloader {
		position: absolute;
		left: -9999px;
		top:  -9999px;
	div#preloader img {
		display: block;
@media print {
	div#preloader img {
		visibility: hidden;
		display: none;

Here, we have the preloader division positioned far to the lower-left outside of the screen, and then redundantly specify block display on the image elements.

Finally, to prevent the unwanted display of these preloaded images via print media, we simply hide the images via display:none; and visibility:hidden; declarations.

When using this method to preload/cache images, remember to call the preloaded images by using the exact same path used for the original preloaded image. For caching to work, the browser must reference an existing resource via the identical path.

This method is designed to enable the caching of specified images in virtually all visual browsing devices. If you encounter cases where this method does not work, or if you have comments or suggestions for improvement, please share by leaving a comment below. Thanks!

About the Author
Jeff Starr = Fullstack Developer. Book Author. Teacher. Human Being.
USP Pro: Unlimited front-end forms for user-submitted posts and more.

45 responses to “Better Image Caching with CSS”

  1. Thanks Donace, will check it out! :)

  2. Instead of setting an outrageous position, why not have a position of 0 0 and set the size of the image to 0 0?

    And you should improve this further to make it hidden even when a person deactivates css on your website. Especially with how easy it is on Firefox.

  3. If I use css background images instead of calling them via will it be cached too?
    In other words: If I use sprites, should I call the image using at least once so it is cached?

  4. Posting the question again since it eats the html tags:

    If I use css background images instead of calling them via the “img tag” will it be cached too?
    In other words: If I use sprites, should I call the image using “img tag” at least once so it is cached?

  5. Jeff Starr 2009/01/27 9:45 pm

    @Cooltad: Some great ideas there. Will have to check them out in cross-browser environment. Not sure about leaving the images at 0 0, but the logic is sound if image size sticks at nothing. For your second point, are you referring to inline styles? If so, I would rather not..

    @John: If you are able, keep your sprite size small and optimized well enough to avoid the need for preloading/caching. Even so, images are cached according to file path. Use the same path as the cached images for CSS backgrounds for successful preloading.

  6. Peter Assenov 2009/02/10 2:24 am

    hi, I think CSS image cashing as shown here could be really useful…
    I’m using another technique that can work together with this one.
    In case you have many small images in the website /icons or thumbnails/ the page loading speed is going down because of the multiple HTTP requests for every one of them. Cashing doesn’t seem to help a lot because the problem is not the size, but the number of images/connections for them/. Even when the browser retrieved the images from the local cash still there is a slowdown.
    In this case you can merge all icons/thumbnail/ in a large image and use background-position to show the appropriate part of it. Of course you can cash the large image with CSS. I’ve noticed that when the images are more than 100 in a page, merging usually helps.
    Hope it will be useful…

  7. Jeff Starr 2009/02/11 8:06 am

    @Peter Assenov: Thanks for the tips! You raise and excellent point about reducing the number of HTTP requests by using sprites. It is an excellent optimization technique that I use here at Perishable Press all the time. For example, if you scroll up to the top-right sidebar panel and view the background image for any of the small icons, you will see how I managed to reduce around thirty HTTP requests for images down to one.

  8. Peter Assenov 2009/02/12 12:59 am

    @Jeff I think you did a great job for Perishable Press. I really like the front-end.

    Also using sprites overcomes the annoying background-image blinking in IE.
    With a little scripting can nice hover animations can be made-, but that’s getting off-topic, sorry.

  9. Well this is definitely a great way to preload images for subsequent pages on a site… I suppose using a sprite for the main page could cure load time for index, then using this method would resolve load time on any further pages.

    I have a question (somewhat off topic) now that I’ve mentioned sprites… Has anyone else had troubles with IE 7 becoming extremely “jumpy” when you scroll down the page if you’re using a sprite for background images (repeating x and/or y)?

  10. Sunny Singh 2009/07/19 3:51 am

    I don’t see any use for this, ever since I started using sprites especially for hovers, there is no need to preload images.

  11. Thierry Koblentz 2009/11/24 8:25 am

    In my humble opinion, this is not caching images with CSS, but caching images with CSS *and* Markup ;-)

    Why the DIV? Why the images?
    Why not simply choosing a few elements on the pages that do not have a background image and style them with the images we want to preload (with background-position:100% 100%).

    If you believe this is not as good because the call is made early (in the HEAD) rather than late (end of BODY), then use simple DIVs rather than images.
    That image markup is a lot of bytes. Besides, images are content, and your example would create issues with screenreaders. Because without a ALT attribute a screenreader speaks the name of the image.

  12. Good post, thanx !
    I made a post about 2 ways to cache JavaScript, CSS and image only : Using your browser’s cache : here :

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 »
Wizard’s SQL for WordPress: Over 300+ recipes! Check the Demo »
Crazy that we’re almost halfway thru 2024.
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.