Complex ideas can be conveyed with just a single image. That’s the notion of the common expression, “A picture is worth a thousand words.”
To provide rich user experiences, today’s web sites are incorporating lots of images. In most cases, these images are high resolution and have larger dimensions than in the recent past. Images contribute more to page weight than any other resource; according to httparchive.org, they represent 62% of the weight on an average web page.
Of course, as the use of images has increased so has the challenge of serving them without adversely affecting the user experience. This post addresses some of the most effective techniques for optimizing the perceived and real load times of image-rich web pages.
WebP
WebP is a new image format from Google with a 25-34% smaller file size compared to JPEG images. Currently, Chrome and Opera are the only browsers that support WebP. According to wikipedia, Chrome has a 36% share and Opera a 1% share of browser usage.
This test from webpagetest.org compares the page load time of WebP vs. JPEG. The test has one page with 50 images in the WebP format, and another page with the same 50 images in the JPEG format. Because the WebP page had to download fewer bytes (474484 vs. 757228), it completes loading much earlier compared to the JPEG page.
If you track your web site’s browser usage stats and find that Chrome/Opera users are a sizable chunk, using WebP images will improve the page load time for these users.
Progressive JPEG
A simple or “baseline” JPEG file is stored as one top-to-bottom scan of the image—whereas the progressive JPEG format divides the file into a series of scans. When a progressive JPEG loads, the user sees a low-quality image at first, but gradually sees the image at its full quality. Most of the latest browsers support progressive JPEGs. They improve the perceived loading speed when compared to baseline JPEGs, as this webpagetest.org test demonstrates.
Try progressive JPEGs for your above-the-fold images, and do A/B testing to see the impact on your site’s user experience.
Lazy loading
The most popular image optimization technique, widely used across the web, is lazy loading. This technique involves loading only a subset of the images initially, and loading the rest of the images on the scroll event or after the window on-load event. Using the on-scroll event to lazy-load images will significantly improve the page load time.
This technique might require the use of JavaScript. The only issue I see with lazy loading is that if the user loads a page through the browser’s back or forward button, JavaScript usage might cause some lag before the lazy-loaded images appear.
Image embedding (Data URI / Base64)
Each HTTP request exacts a price. Another popular technique for improving page load time is to minimize the number of HTTP requests. To improve the perceived load time, you can embed above-the-fold images using the Data URI scheme (base64). With this technique, images can be delivered as part of the page’s main payload; the HTTP request can be eliminated completely. Consider, for example, this <IMG> tag, which uses an HTTP request to display (a right arrow):
<IMG src="http://pics.ebaystatic.com/aw/pics/help/infohubs/images/imgNaviArrowRgt_12x12.gif">
The following <IMG> tag uses the Data URI scheme to embed the image in the page:
<IMG src="data:image/gif;base64,R0lGODlhDAAMANUmACxw0RZVtClvzhxevA1OqApFoQQ/mxFMqARBnApFnxVWsipxzRZXsyFmwRxfugVIoSNlwx1fvStv0BZWsAA9lAA8lApHoA9PpwNAmSduyilsxx5dvCRlwxxevhRXsiNkwidsyRFOqSFmxQ5Nqidsyxpfuv///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACYALAAAAAAMAAwAAAY6QJPQJBkajQDB8ShYAJZDUkYDgpo+EE5DBO2UNgNHZKnwBBiBwXIUOhAmUMujcLFiEAmrqWLQmyhQQQA7">
The Data URI approach has two drawbacks: the main payload of the page is increased, and the images aren’t cached by the browser. To address the caching issue, you could deliver Data URIs via an external JavaScript or CSS file; but you might not see the same perceived speed improvement that you would if you embedded the images directly in the page.
Sprites
Sprites are another way to minimize the number of HTTP requests. With this technique, you “stitch” together different smaller images and display the stitched image on the page, using CSS background styling to show different parts of the image. Sprites are easier to implement in cases where fairly static sets of images are to be displayed. Applying this technique to dynamically constructed pages—such as a search results page, where images to be displayed can vary substantially over time—could be challenging. The stitching process would need to be on demand and very fast. Moreover, if you’re using a content delivery network (CDN), you might lose the CDN benefits, because the stitched images might not be in the CDN cache servers and so the requests would come to your app servers instead.
CDN
By serving all static resources for a web page through a CDN, you can significantly reduce the actual page load times. Instead of the static content being requested from your servers, it would be delivered from CDN cache servers that are closer to the end user. Using the same images across all of your web pages would increase the CDN cache hits.
Domain sharding
Traditionally, web browsers place a limit on the number of simultaneous connections they can make to one domain. To increase the number of simultaneous connections, you can use multiple domains to serve the resources. You would have to pay for extra DNS lookup time for these extra domains, but the benefits outweigh this overhead. Domain sharding is applicable to all external resources—not just the images.
For mobile use cases, domain sharding might not be optimal, because the connection overhead for mobile browsers exceeds the benefit of having additional simultaneous connections.
Image dimensions
Specifying the width and height of every image in the <IMG> tag or in the CSS avoids unnecessary reflows and repaints. For example:
<IMG src=” http://thumbs.ebaystatic.com/d/l225/m/mHpX0W1OpQlEaydbGwCWuOg.jpg” width=”208px” height=”126px”>
This practice improves the rendering time and provides the user with a much smoother rendering experience.
Image scaling
If you need a smaller image, scale the bigger image and create the smaller one. Avoid using width and height specifications to scale images on the fly—a practice that would require downloading unnecessary extra bytes, thereby increasing page loading time.
Here is an example of poor practice:
<IMG src=”bigimage_width300_height300.gif” width=”100px” height=”100px”>
Instead, generate a 100 x 100 image, and use it:
<IMG src=”resized_bigimage_width100_height100.gif” width=”100px” height=”100px”>
The generated image will be smaller in size.
Image pre-fetching
If you can guess the user’s next move, you can pre-fetch some images (maybe the above-the-fold images) for the next page in the idle time or after the current page is loaded. This technique would load the next page faster, since the pre-fetched images would come from the browser’s cache.
Conclusion
To provide rich content, images are king. The optimization techniques discussed in this post are widely used across the web. By adopting all or some of them, you can substantially improve the perceived and real page load times for your site. Personally, I am thrilled about WebP and progressive JPEGs, and I hope more browser providers will come on board to support WebP in the future.