Preloading On-Demand Images with CSS

Posted September 15th, 2006 by Mike Cherim

Onmouseover and onfocus events in JavaScript, and :hover and :focus pseudo element actions using CSS, open up a world of interactivity on the web for both mouse and keyboard users alike using most browsers. (I wrote most browsers because IE doesn’t recognize the pseudo element :focus and must use :active, and that’s only on anchors.) Font colors can change, backgrounds can change, static images can be replaced with new images. In fact, swapping out imagery can be the root of some of the more creative uses. But like everything, the more you offer means the more it can cost in terms of user resource demands and smooth interactivity.

This is key, because if these events or actions trigger flashes or halted motions, it can detract from what would ordinarily be a pleasurable user experience. This is especially true when it comes to swapping out images for the simple reason that images must load to be viewed. With respect to web users without fast connections like broadband or quality DSL, simple actions like swapping out images via JavaScript or CSS can lead to some horrendous effects. Take, for instance a link with a static grayscale image background that’s meant to deliver a color background image when the user hovers over or focuses on it. Ideally we want this transition to be instantaneous. The last thing we want is to have the image begin loading at this point. Thus we need to preload the secondary image.

This can be done using a JavaScript preloading technique, a good method if JavaScript is supported. Another method, using CSS, employs a single, multi-part image re-positioned differently depending on its state; this is a great method especially for block link backgrounds. And then there’s a way of getting this done using CSS with display:none but I think this technique is flawed in that it doesn’t really load the image — at least I couldn’t find it on my Page Info > Media list (using Firefox) when I tested this.

All these methods aside, though, beneficial or flawed, I’ve long had my own method of doing this with CSS that has its own benefits. My method is especially useful for larger images like mastheads or banners in that the technique serves two purposes. My method uses an absolutely positioned offset class to get the replacement image off screen and out of sight while still allowing it to be downloaded to the browser. Now using absolute positioning for preloading is not a new technique, but how I the incorporate the replacement image into mark-up may be unique.

A lot of developers offer background images as image replacement for text. It often looks better than plain text and it’s a nice site design method. I do this a lot myself. This way I don’t have to worry about the visitor having a particular fancy font- or type-face. Most of the time I offer a second image which is available on hover or on focus. I don’t do this here on my blog, but I do on the inner pages of my SeaBeast theme for example. (Hover over or click on the masthead image to see it change, then turn off styles to see the preloaded image sitting nicely at the top of the page). What I do in that case is offer the secondary image as an offset image embedded in the markup, right where the masthead should be. This method provides a decorative masthead image if styles aren’t supported all while effectively preloading the secondary image to reduce the halted load effect. This may be something some people will like while others will not. There are advantages and disadvantages, as follows:


  • Preloads the secondary image to allow for smoother interaction.
  • Requires no user-side scripting support.
  • Can provide an important identity element like a logo.


  • Embeds an image in the mark-up (some purists won’t like that).
  • Supports only two images unless two offset techniques are combined.
  • Width of image sets a minimum width of its parent(s).

The How-To

Here’s an example of how something like this can be marked up, there are many others ways to do this as is the case on my SeaBeast theme’s inner pages (linked above) where I included the image above of the jump links and heading element, but with this example you’ll get the idea and that’s what I’m after.

 <-- XHTML -->

 <h1><a href="/">
  <img class="offset" src="images/masthead.jpg" width="760" height="200" alt="" /><br />
   <span><-- (this span is for an image replacement technique) --></span>

<-- CSS (for embedded image offset class only) -->

 img.offset {
    position : absolute;
    top : -9000px;
    left : -9000px;

Notes: The alt attribute is left null as the text is supplied directly beneath it if styles are off so it’d be redundant. The break <br /> is added to keep the text underneath the embedded image if styles are off.

6 Responses to: “Preloading On-Demand Images with CSS”

  1. Neal V responds:
    Posted: September 15th, 2006 at 7:31 pm

    Nice, man. I’ve had that problem before, where the first image on a roll-over is spastic while the image loads.

    My only problem, though, is that you are using, ahem, inferior (I think) image replacement. Don’t you know that BIR is where it’s at? Hmm, perhaps I should rename it to NIR, since I’ve dropped my old moniker.

  2. John Faulds responds:
    Posted: September 17th, 2006 at 10:32 pm

    BIR actually seems to be close to the Gilder/Levin IR method but has a problem with the text sticking out when the text size is increased.
    Both have probably been superceded by the Gilder Levin Ryznar Jacoubsen IR method.

  3. John Faulds responds:
    Posted: September 18th, 2006 at 5:02 am

    Just had a quick test with overflow: hidden on the BIR method and it doesn’t seem to prevent the text appearing on text resize and actually makes the text appear above the image in FF in some situations.

    The em is required if you’re concerned about your image replacement working in IE5Mac, otherwise you can use a span. Most of the other IR methods I’ve seen that use an extra element usually involve it being empty, so in those cases I don’t see an empty em as being any less semantic than an empty span.

Sorry. Comments are closed.

Note: This is the end of the usable page. The image(s) below are preloaded for performance only.