Wednesday, March 10, 2010

Latency, Requests, CSS Sprites, and You

Ah yes, more website optimization talk. I love this stuff.

Did you know that often times the slowest part of loading a web page for the first time can be attributed to the inherent latency and overhead from the requests themselves? In fact, most modern web pages consist of much more than a single html file. Most pages also have an external css file, sometimes a js file or two, and multiple images. It's not uncommon to see over 20 files altogether necessary for just one web page. Edmunds.com, for example, has over 40 files on their home page.

The problem with this is that each and every file must be requested by your browser individually. So what? Well using Fiddler I've gathered the first request header that's sent when I go to www.google.com:

GET http://www.google.com/ HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
Accept-Language: en-US
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; GTB0.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; OfficeLiveConnector.1.4; OfficeLivePatch.1.3)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: www.google.com
Cookie: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
That amounts to 1,036 bytes of data.

And here's the response header:

HTTP/1.1 200 OK
Date: Wed, 10 Mar 2010 19:45:31 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=UTF-8
Content-Encoding: gzip
Server: gws
Content-Length: 4497
X-XSS-Protection: 0

That's 220 bytes.

From what I've observed in request/response payload alone you can expect an average of 800 bytes to 1,600 bytes of additional fluff for every file. In our hypothetical page above with 20 files for a given page, that amounts to 16,000 to 32,000 bytes. In addition to this extra fluff that's being sent back & forth you also have to take into account network latency of the connection itself. Each of these files require a connection of its own. A connection is normally established in a matter of milliseconds. But again, when dealing with multiple files it adds up.

The part of this story which was a big eye opener for me is when you're dealing with tiny files. I often use 1-pixel wide images for gradients and such which amount to a couple hundred bytes. Say for example you create 4 of these tiny gradient images. Well, that extra fluff from the request/response we talked about might easily be 5 times the size of the image itself.

If you're like me then I've officially shaken the very foundation of everything you thought you knew about website optimization. So what can you do about it?

Well, I'd highly recommend downloading Yahoo's YSlow plug-in. It's designed for Firebug in Firefox. After you install it, bring up your website in Firefox and run YSlow and see what it says. It offers excellent advice on a number of common issues that can affect performance, some of which are very easily solvable.

As for advice on this topic specifically there are a couple things you can do:

1.) Create CSS Image Sprites. The idea here is to combine images or icons into one bigger image, and then use clever CSS background positioning to show each image appropriately. This can drastically reduce the file count. And although it requires a lot of extra effort, it can be well worth it.

2.) Host your external css, js, and images on a cookieless domain. If your site doesn't use any cookies to begin with then you won't need to worry about this. But if it ever sets cookies then storing your images on a separate domain that's dedicated to static content can drastically reduce the payload of every request. Just look at the Google request header above and you can see that half of its size comes from that cookie.

This whole concept of request/response overhead may change your approach to a lot of things. But it's important not to take this too far. There's still a strong case to use external js and css files, for example. Any time you have multiple pages that point to the same resources you have the advantage of caching on your side. I talk a little about that in my other website optimization article. But CSS sprites and cookieless domains mentioned above are both valuable techniques with very few downsides.

0 comments: