Feb 26, 2010

HTML Sprites - silver bullet against small images

Last builds of WEBO Site SpeedUp include amazing client side optimization approach - CSS Sprites for HTML images. Let's review underneath logic and all related techniques.

CSS Sprites - why HTML?

Actually we are speaking about combining images to a larger one which can be positioned with CSS property background-position. It's impossible to convert raw HTML images to CSS Sprite (to be correct - it's possible but leads a lot of restrictions and drawbacks, i.e. we will have to drop a huge part of images' functionality and properties).

So before any actual operations with images in HTML code (like <img src="..." />) we should prepare them. How? We should convert all images to 'fake' ones - transparent stubs which have initial image as a background, and the same width and height.

Converting HTML images to CSS images

Well. To reduce amount of data (we are going to speed up website, not to increase its load speed) we should choose very efficient approaches to insert transparent stubs. And we have 2 choices:

  • Insert call to 1x1 transparent GIF image (yeah, bad known spacer.gif which was used a lot several years ago to make table layout). Its size is only 43 bytes (but 1 more HTTP request).
  • For modern browsers we can use 82-bytes data:URI chunk (which represents this image - data:image/gif;base64,R...Ow==. A bt more data (with gzip usage - about 100 bytes for 1 HTML document, or nothing). But minus 1 HTTP request (cool!).

To provide the best practices here we can combine both approaches - for IE7 and lower use the first one, for all the other browsers - the second one.

Playing with HTML Sprites

It seems now we have all parts for HTML Sprites logic and can reveal it.

  1. First of all - parse initial HTML code to find all images, get their sizes (and skip some large ones).
  2. Then create an array of CSS rules based on given HTML images - just background image (plus no-repeat and zero background position), width and height.
  3. Then just combine all images in 1 CSS Sprite (using existent CSS Sprites logic over current set of CSS rules).
  4. Finally (with a number of CSS classes) replace initial HTML images with stubs with calculated styles.

All this looks very simple. But what are drawbacks?

Troubles and solutions

As far as we need to check size for any image (just to get its dimensions an skip it if it's very large) - we will have a lot of I/O requests with any HTML document. So this can significantly increase server side load time. That's bad. But we can cache calculated dimensions for known images (such dimensions are being changed very rarely) - and skip all future recalculations.

But with every HTML document (with cached calculated dimensions) we have one more expensive CPU operation - CSS background positions calculation (even with completed CSS Sprite we need to get actual positions of given images inside it). But good news here is that we can also cache such calculations (to a set of CSS rules for given HTML image).

Also we must have per-page or per-website modes. Just because you can have thousands of small images through the whole website - but you don't want your visitors to download them all at once.

With all such approaches HTML Sprites technique works both on a high-end servers and weak VDS/shared hosting. And reduces by 20-30% number of HTTP requests for every your web page. That's really amazing. And it's ready to use - just download WEBO Site SpeedUp or update to the latest version.

1 comment: