In the inaugural topic of this blog on site speed, Hugh Williams spoke briefly about image spriting as a technique to speed up the rendering of a page. CSS Image Sprites are now commonly used to remove the performance problems created by making separate HTTP requests for every image on a web page. Unfortunately the technique cannot be used on a web page with a dynamic image set such as the eBay search results page: the images on the page change with every request based on the item specifics, therefore combining them into one sprite image is not possible.
When brainstorming alternatives, we found what seemed to be an obvious solution: the image Data URI scheme. It works in all major browsers (except IE6 and IE7), and it solves our problem of too many HTTP calls. The code looks like this:
background: url(data:image/png;base64,) no-repeat;
Though the Data URI scheme solved our original problem, it created two new ones:
- A much larger HTML payload, since the images are now embedded in the page
- A loss of browser cache benefits: all images are sent over the wire on every page request
We realized what we really needed was a combination of the two approaches, because we would then be able to create image sprites dynamically. So we wrote urigen, a simple web service that generates a base64-encoded image data URI scheme response in JSON format for a given set of image URLs.
Under the hood
For a page with a dynamic image set, the browser calls the urigen web service immediately after the page load event with the image URLs passed as GET (or POST) query string parameters. The web service then extracts the image URLs from the query string, makes HTTP calls to the image hosting servers, does a base64 encoding on the response, builds a JSON array and returns it as shown below.
Data URI sprites can be effectively used for dynamic images below the fold on a page, or for images that are shown on demand based on user actions.
- The JSON response should have the appropriate HTTP cache headers to benefit from browser caching, if the same URLs are requested again
- If the service is hosted on the same web server that is hosting the images, HTTP calls (from web service to image server) and their associated latency can be avoided and images can be read from the disk locally.
- The web service should have a proper LRU caching mechanism in place to avoid repetitive calls for the same image and instead retrieve data from the server cache
- The urigen web service itself can be a server side call from the page and the data sent as a separate below-fold chunk after the main page is flushed out
Engineering Lead & Site Speed Evangelist