So, You Want To Pre-Load, Huh?

By Joe Burns

Image Preloading using HTML5, CSS, and JavaScript

Image Preloading using HTML5, CSS, and JavaScript

Original article by Joe Burns, updated by Rob Gravelle

Have you ever noticed that pages you've already visited always load faster than one that you're viewing for the first time? The reason that page content loads so fast the second time around is that they've been cached by the browser. The first time that the browser opens a page, that HTML document and associated resources are all written to the cache for later use. The next time you navigate to that page, the browser knows it can load the page and resources from the cache rather than re-fetching the files from the server.

Knowing that downloading an image primes it for faster delivery on the next request, we can force the browser to download images for later use early on in the page loading process. That technique is called image preloading and is the subject of this tutorial.

Advantages of Preloading

The primary reason that you would want to pre-load images would be to increase responsiveness, as in, decrease noticeable time lags. You might think that, in this day and age, most people have a fast enough connection to make image preloading unnecessary, but that's not entirely true. Consider the mouseover event; if you change image on the :hover state, downloading will only be initiated on the first :hover event. Hence, there may be a perceptible delay there. Large image files may also take a second or two to load. Preloading those images early rather than later helps ensure that visitors have a great experience viewing your content.

A Few Caveats

Caching pages is a good practice, but don't go overboard. Caching every image up-front will certainly take longer than just downloading the current page images and such. You can try to get around that by only caching what will be needed for the next few pages rather than trying to squeeze everything through the Internet pipe at once.

Another consideration is whether you're preloading using HTML, CSS or JavaScript. As we'll see shortly, each has their own pros and cons. For instance, preloading with CSS tends to make fewer HTTP requests than JavaScript and works even if the user's browser has disabled JavaScript (not that anyone does that anymore!). CSS-driven image preloading may also help speed up the rendering of your site as you probably already have a bunch of JavaScript running on the page load.

With that in mind, let's explore each technique in detail.

HTML Preloading

Most commonly utilized to define a link between a document and an external resource, such as a CSS file, the <link> tag also provides a mechanism for performing predictive lookups and fetching of resources. The latter includes a couple of options for preloading images, one that's been around for a while, and another that's much a more recent addition.

Let's begin with the most established one. It sets the rel attribute to "prefetch", using the following basic format:

<link rel="prefetch" href="(url)">

This directive tells the browser to fetch a resource that will probably be needed for the next navigation. That means that the resource will likely be fetched with extremely low priority since everything that's required in the current page takes precedence over a resource on the next page. That makes prefetch far more suited to speeding up the next page rather than the current one.

On the other hand, the new "preload" rel value targets current navigation. It also supports the extra "as" attribute, that tells the browser what it will be downloading. Possible "as" values include:

  • "script"
  • "style"
  • "image"
  • "media"
  • "document"

We can use preload to load images ahead of time, along with the media attribute in order to restrict the downloading of an image to devices of a certain resolution:

<link rel="preload" as="image" href="map.png" media="(max-width: 600px)">

While the prefetch directive is supported by most major browsers, with the exception of Safari and Opera Mini, preload is only supported by Chrome and Opera, making it too early to adopt right now.

CSS Preloading

CSS has been a viable way to preload images ever since the inclusion of the background-image attribute. Since then CSS2 and CSS3 have continued to add ever more options.

As you contemplate using the following techniques, consider that:

  • You may have to also employ a bit of trickery such as setting the visibility to hidden and or position elements off-screen.
  • Preloaded images may only load after all of the HTML page content. Case in point, the photo-full.jpg image below was loaded using CSS. As you can see, it loaded, but only after visible page content:

chrome_network_tab.jpg

Therefore, when you need the image to be available will determine whether to use a CSS-only solution. Unless you need an image right away, it should suffice.

CSS3 Solution

This is the most cutting edge solution at this time, using the :root (or body) selector along with the :before or :after pseudo-selector. Both the :before and :after selectors have an attribute named "content" that can be set to one or more URLs, allowing us to preload all of our images with one rule. This technique works great in supportive browsers now, with support only getting better as time goes on. It also works regardless of document structure because images are associated to an element that is guaranteed to exist - the entire document:

<style>
/* body:before will also work
 as will body:after */
:root:before {
  content: url(/@/Storage/_files/68/file.jpg)
           url(/@/Storage/_files/62/file.gif)
           url(/@/SiteBuilder/_skins/5/images/menu/ro/photos.gif);
  /* partial fallback */
  background-image: url(/@/Storage/_files/68/file.jpg);
  visibility: hidden;
  position: absolute;
  left: -999em;
}
</style>

Notice that we can include a partial fallback mechanism by preloading one of the images as a single background property value. Browsers that don't accept multiple URLs will fallback to the single-value background property instead.

We are also using a few tricks to prevent the images from displaying right away, including the use of "visibility: hidden". It has been found to be more reliable than "display: none", which could prevent the preloading of the resource. Finally, the image is positioned off-screen just in case that it were to display after preloading.

Keep in mind that Internet Explorer (8+) only supports the content property if a valid DOCTYPE (<!DOCTYPE HTML>) is specified.

Setting an Element's Background Image(s)

An alternative to setting the content of a :before or :after pseudo-selector is to set an element's background image(s). The following example uses the shortcut background attribute, of which background-image is one property, along with the repeat and positioning properties. Much like the content attribute, background accepts multiple URLs in most modern browsers, except that these are separated by commas:

body {
        background: url(/@/Storage/_files/68/file.jpg) no-repeat -9999px -9999px,
                          url(/@/Storage/_files/62/file.gif) no-repeat -9999px -9999px,
              url(/@/SiteBuilder/_skins/5/images/menu/ro/photos.gif) no-repeat -9999px -9999px;
  /* partial fallback */
  background: url(/@/Storage/_files/68/file.jpg) no-repeat -9999px -9999px;
}

Again, off-screen positioning is employed to prevent images from displaying after preloading.

JavaScript Preloading

JavaScript includes the Image among its native object types. The Image object represents an HTML image tag on the page and exposes the same properties and events. Perhaps oddly, the Image has no constructor that accepts an image source, so an image must be loaded into the object by setting its src attribute. Doing so causes the image to be downloaded from the server at that point.

<script type="text/javascript">
var my_image = new Image();
my_image.src = 'mycoolimage.jpg';
</script>

Once an image is preloaded with JavaScript, you can take advantage of the cached image using only its filename. It's not necessary to keep using the JavaScript variable that you loaded the image into. The thonky.com provides an excellent demo to illustrate this. The demo provides a button to preload the image. After it has finished loading, the page displays a second button that allows you to use the preloaded image in an image tag, using only the image filename. Even though the code does not refer to the variable that the image was loaded into, the image will still show up right away because it's in the cache.

Here is the code behind the demo, for your convenience:

<script type="text/javascript">
var my_image2 = new Image();

// notify the user that the image has been preloaded, and reveal the
// button to use the preloaded image
function notify()  {
    document.getElementById('preloadbutton2').style.display = 'none';
    document.getElementById('after_preload').style.display = 'block';
}

function preload() {
    my_image2.onload = notify;
    my_image2.src = 'bigsaturn.jpg';
}

// using only the file name, we can take advantage of the preloaded image
function use_preloaded_image() {
    document.getElementById('saturnplaceholder').src = 'bigsaturn.jpg';
}
</script>
<input type="button"
    id="preloadbutton2"
    value="Preload Image"
    onclick="preload();this.value='Loading. Please wait...'" />

<div id="after_preload" style="display: none">
<input type="button" value="Use Preloaded Image"
onclick="use_preloaded_image()" /><br />
<img src="blank.jpg" id="saturnplaceholder" width="500" />
</div>

Conclusion

There is no right or wrong way to preload images. The technique that you employ should be tailored to your particular goals. When testing your chosen technique's efficacy, check the browser's network monitoring utility in the developer tools. It will help you ascertain whether or not image preloading is working how you think it is. In a future article, we'll take a look at more advanced techniques as well as some excellent image preloading frameworks available.



Rob Gravelle

Rob Gravelle resides in Ottawa, Canada, and is the founder of GravelleWebDesign.com. Rob has built systems for Intelligence-related organizations such as Canada Border Services, CSIS as well as for numerous commercial businesses.

In his spare time, Rob has become an accomplished guitar player, and has released several CDs. His band, Ivory Knight, was rated as one of Canada's top hard rock and metal groups by Brave Words magazine (issue #92) and reached the #1 spot in the National Heavy Metal charts on Reverb Nation.



Make a Comment

Loading Comments...

  • Web Development Newsletter Signup

    Invalid email
    You have successfuly registered to our newsletter.
  •  
  •  
  •  
Thanks for your registration, follow us on our social networks to keep up-to-date