Developer Network Home - Help

High Performance Web Sites: Rule 1 - Make Fewer HTTP Requests (Yahoo! Developer Network blog)

« Introducing the Yahoo! Mail Web Service | Main | This Slide Rule Hack That Rules Them All »

High Performance Web Sites: Rule 1 - Make Fewer HTTP Requests

April 3, 2007

In The Importance of Front-End Performance, I reveal that 80% of the end-user response time is spent on the front-end. Most of this time is tied up in downloading all the components in the page: images, stylesheets, scripts, Flash, etc. Reducing the number of components in turn reduces the number of HTTP requests required to render the page. This is the key to faster pages.

One way to reduce the number of components in the page is to simplify the page's design. But is there a way to build pages with richer content while also achieving fast response times? Here are some techniques for reducing the number of HTTP requests, while still supporting rich page designs.

Image maps combine multiple images into a single image. The overall size is about the same, but reducing the number of HTTP requests speeds up the page. Image maps only work if the images are contiguous in the page, such as a navigation bar. Defining the coordinates of image maps can be tedious and error prone.

CSS Sprites are the preferred method for reducing the number of image requests. Combine all the images in your page into a single image and use the CSS background-image and background-position properties to display the desired image segment.

Inline images use the data: URL scheme to embed the image data in the actual page. This can increase the size of your HTML document. Combining inline images into your (cached) stylesheets is a way to reduce HTTP requests and avoid increasing the size of your pages.

Combined files are a way to reduce the number of HTTP requests by combining all scripts into a single script, and similarly combining all stylesheets into a single stylesheet. It's a simple idea that hasn't seen wide adoption. The ten top U.S. web sites average 7 scripts and 2 stylesheets per page. Combining files is more challenging when the scripts and stylesheets vary from page to page, but making this part of your release process improves response times.

Reducing the number of HTTP requests in your page is the place to start. This is the most important guideline for improving performance for first time visitors. As described in Tenni Theurer's blog Browser Cache Usage - Exposed!, 40-60% of daily visitors to your site come in with an empty cache. Making your page fast for these first time visitors is key to a better user experience.

Steve Souders

[Steve Souders is Yahoo!'s Chief Performance Yahoo!. This is one in a series of Best Practices for Speeding Up Your Web Site. This article is based on Steve's book High Performance Web Sites, published by O'Reilly.]

Posted at April 3, 2007 9:41 AM

rss     Add to My! Yahoo

Comments

Great tips, thanks!

Re: inline images. Unfortunately they are not supported in IE6/7
http://en.wikipedia.org/wiki/Data:_URI_scheme

Posted by: Stoyan at April 4, 2007 3:02 PM

First off-- GREAT book.

Second, yeah, I spent so much time trying to sort out inline images. Just no way to get it across all browsers. I did, however find a decent way, where Javascript converts a text-encoded image into a table with colored pixel-sized cells. It avoids the download of all the table info by rendering after loading. Now, of course, I can't find it, but I think it could be improved, it only uses run-length-encoding now.

Posted by: Morgan at April 4, 2007 10:49 PM

Found it: http://www.bennherrera.com/EmbeddedImage/

It's interesting if nothing else.

Posted by: Morgan at April 4, 2007 10:56 PM

Great tip, however as good as it is to make things faster for 'first-time' visitors, there is a compromise that needs to be made. While combining all scripts into one script and all CSS files into one CSS file reduces the number of HTTP requests, there is another problem in addition to the one mentioned about pages using different scripts and styles. Namely, maintenance.

I commonly use two scripts and two CSS files per page. One script file is for scripts that are common across all pages, while the CSS files are one for layout and one for presentation. I could easily combine the two CSS files, but in order to ease maintenance and changes they are divided up. So there is a compromise between speed and maintenance.

In addition to that there is the size of the combined files to consider, how much speed is gained by reducing the script requests to one and the css requests to one versus the time taken to download the larger files?

The question you need to ask yourself is, is the small amount of speed gained by combining all scripts into one file and all CSS into one file worth sacrificing maintainability, if not how can I compromise between the two? That's a question that should be asked with all of these tips, especially with the ever increasing usage of broadband connections.

Posted by: Michael at July 26, 2007 9:10 AM

You can and should get the best of both worlds, maintainability AND the fewer HTTP requests that result from combining the CSS files. How? Make the combining part of your site build process that you go through when releasing a new version of your site. Don't have a site build process? Then you have bigger problems, or, it could be said, smaller problems, since your current scale probably means you don't need to worry about boosting performance in this manner.

Posted by: PK at July 27, 2007 9:00 AM

Michael - That's a very good assessment of the situation. And a great reply from PK.

If you have a variety of pages that use a different set of scripts and stylesheets, you should _not_ combine them all into a mega-file. That's inefficient because a single page is downloading more JS and CSS that it really needs. Try to find a compromise - maybe 3-5 combo scripts and stylesheets that will cover most of your pages with little or no unneeded JS and CSS being downloaded.

Combining the files as part of the build process is a good idea. I prefer combining them on-the-fly (with caching so the concatentation step is only performed once). This gives the frontend developers more flexibility.

Posted by: Steve Souders at July 28, 2007 10:41 AM

Kind of ironic that this page only gets a 66 or "D" on YSlow. :)

Posted by: adampasz at August 5, 2007 5:18 PM

A redesign of YDN that includes performance improvements is in the works! ;-)

Posted by: Steve Souders at August 20, 2007 2:25 PM

What is your thoughts when it comes to using YUI? I've got a lot of pages that utilize six to eight of the YUI js files. Is it better from a performance viewpoint to utilize Yahoo's ability to host these files (not from my site, gzipped, expire headers, etc.) or would it be better to take these six to eight files and combine them into one file thus reducing http requests?

Posted by: Chris at August 27, 2007 4:27 PM

I bet that's a wash. I believe there's a "combined" version of the YUI libraries, but it might pull in more than you need.

Posted by: Steve Souders at September 5, 2007 11:29 AM

How do you combine CSS files during the build process while able to work on separate CSS files during development? For example, during development, I use 5 separate CSS. So that means, in my HTML code, I have 5 tags inside my tag.

Now, when the 5 CSS files are combined via a build script, my 5 tags must be changed to a single one that refers to the combined CSS file. Where does this step fit into the build process and keep good maintainability?

Posted by: James at September 7, 2007 4:20 PM

James: In my book I have psuedo code for inserting scripts (or stylesheets). I recommend, if you're using some HTML templating system like PHP or even Perl, that you never have a SCRIPT SRC, LINK, or IMG tag in your templates. Instead, use a function in your templating language such as "insertScript('/js/header.js')". This function would output the appropriate SCRIPT (or LINK or IMG) HTML.

Doing this through a module that you control addresses several features: If your hostnames change, you can update all your URLs in one function (ok, maybe three functions). You can make sure you don't include the same .js or .css more than once. To your specific question, while in development mode you can include each .js or .css as separate files, but in production mode you can instead construct a URL that combines them all into one SCRIPT SRC or LINK request, and let the backend do the combining.

Posted by: Steve Souders at September 9, 2007 5:00 PM

My friend Aaron wrote up a nice article that talks about this, including a trick for increasing the number of concurrent connections the user maintains. See: http://www.die.net/musings/page_load_time/

Posted by: John Callender at September 11, 2007 4:15 PM

On my blog http://blog.aujava.com/?p=29 I have posted minimalistic JSP scriplet that allows you to combine and serve out as one chunk several JavaScript or CSS files with names passed as params. Gain extra 15 points with YSlow.

Posted by: Robert Sayfullin at September 12, 2007 9:21 PM

Regarding use of data: to embed images into html remember that IE does not support this which will render it useless for most users unfortunately.

Some more info http://en.wikipedia.org/wiki/Data:_URI_scheme

Posted by: Leo at October 6, 2007 7:37 AM

I think what's important here is that developers know their users and develop for them. It's wrong thinking to believe that 'everyone' needs and will access the site. Know your users.

Posted by: brandon at October 10, 2007 10:16 AM

Shall i combine utilities.js + container_core-min.js + menu-min.js into yui-sulekha-common.js? I tried this; But, get js errors like, YAHOO.widget.Panel is not a constructor. Is there a way, i can combine the most used yui control's js into a single js, so that the number of http request is reduced?

How do i make a single call for all required yui control's js?

Thanks in advance for your kind suggestions.

Posted by: Mahadevan at October 15, 2007 7:19 AM

Yes, combining the YUI files into a single file is a good idea. Double-check what you did - if the individual files can be loaded, then the combined version should work, too.

-Steve

Posted by: Steve Souders at October 15, 2007 9:23 AM

Sprites are great, but if you have images turned off or are on a screen-reader then over use of this technique could cause problems. Prime candidates for sprites are images that are presentational (i.e. icons, gradients) as opposed to informative (a graph, or something that would require an alt/title tag). What are other people's thoughts on when/when not to use sprites?

Posted by: Rob at October 29, 2007 8:22 AM

What is better for a gradient background image? to use a 1 single image as a gradient coloured background, or to use a one light slim image for a line, and repeat it several times to get the whole picture of the background image? Does the second approach increase the number of HTTP requests???

Posted by: Hanan at November 2, 2007 11:49 AM

Another critical point is to use URIs/URLs consistently as detailed in the Caching Tutorial by Mark Nottingham.

Basically to point to a certain location (eg root/home), always use the same resultant path — eg "/" for absolute path or "../" for relative path (to go up one directory) — don't use "/index.ext" (ext being the file extension, eg .html .php .xhtml .xml or whatever) on some pages as URLs are the primary way that user-agents/HTTP-clients distinguish resources.


In response to Rob (Oct 29th) it would be better to use the smallest image possible (preferably a 1x1), then "stretch" it with CSS. This allows the size of the rendered element to be flexible (imagine a user resizing their browser window, or you the author wanting to change the dimensions of the gradient-filled box), and greatly reduces the amount of image data needed (certainly the largest resource data-wise), the few dozen extra bytes in your CSS file will be negligible.

Posted by: Lee Carré at November 25, 2007 4:06 AM

Seems the comments system stripped my link markup.
Mark's Caching Tutorial: http://www.mnot.net/cache_docs/

Posted by: Lee Carré at November 25, 2007 4:07 AM

This performance point is a little "hand-wavy" for me. Let me explain. All of the bandwidth savings from reducing the number of HTTP requests comes from reducing HTTP headers. Because browsers use persistent connections, that's virtually all the savings. Sure, you can eliminate stuff from external domains (where the persistent connection might not matter versus a non-persistent one because you're more often only transferring a file or two), but the main way to reduce connections is to combine files on your own servers, where the persistent connection will be fully active.

Typical HTTP request and response headers are about 400 bytes each, so you do save 800 bytes on each file. Depending on the size of the files you're using on your site, that may or may not be a lot. It's certainly a factor, but I wish the point would discuss it in that level of detail.

Posted by: Adam Fisk at December 5, 2007 9:25 AM

Hi, Adam. Just combining scripts has resulted in a 10% response time reduction in our tests, even though Keep-Alive was used.

Looking more at HTTP headers: I use yahoo.com a lot, so my HTTP headers would be big (because of cookies). So instead I looked at google.com. (I use it a little bit for the Firebug group, so have a few cookies.) My request headers are about 1450 bytes. The response headers ranged from 200-550 bytes. So real world web apps might have bigger headers than expected.

Keep-alive greatly improves performance, but having a single request is even faster.

Posted by: Steve Souders at December 5, 2007 3:59 PM

Unfortunately our site is getting an F. Some time ago we went to iframes on one of our web part pages becuase the third party grid control we use does not play well with asp.net web parts and causes serious memory leaks. So now we have up to 8 web parts (each with one iframe) which holds this third party component and requires 6 js files for each frame! Obviously we have a problem with Http requests... any suggestions outside of scraping either web parts or the third party component?

Thanks.

Posted by: Chris at December 22, 2007 8:04 PM

Hello

thanks so much for the tip, I read them part very carefully , but till now I did not know if I have 4 images on my web site and I need to add future expire header in three of them and let the forth wi no expire header , how can I do that ? can It do that from the IIS layer or can I do that via the HTML code on each image?Please elaborate
Please advise.

Thx
Reham

Posted by: reham at January 11, 2008 7:47 PM

Thanks for the response, Steve, and interesting point on the size of headers due to cookies. I had not thought of that -- cookies certainly could add a great deal to header sizes. This whole site has given me far greater respect for the intricacies of browsers' efforts at optimization.

I'm used to dealing with big files in p2p land where headers really make little difference. I can't count the number of times I've defended HTTP as a protocol on p2p lists largely on those grounds. With the small files browsers deal with, though, it certainly makes sense headers would make at least some difference, particularly with the larger header sizes due to cookies, as you mention.

That brings up another theoretical optimization -- reducing the size of cookies. It might make sense in certain cases to gzip data in a post request body rather than use a lot of cookies. As I understand it, browsers always include whatever cookie data there in a header, though, so it might not be practical when you need persistence.

Posted by: Adam Fisk at January 16, 2008 11:43 AM

Thanks Steve for sharing share a nice information.I am working in LAMP environment and just want to is there a way to add expired header to a script in html i mean while defining script tag?
one more question is there any way to avoid browser to check whether file got modified or not,i mean to avoid header to check the latest modified date for cached file?we can make file url dynamic so that browser fetched the file when it get modified rather than sending header every time to check modified date for a file.I think this way we can avoid unnecessary headers.

Posted by: Nadeem Agaskar at January 19, 2008 11:09 AM

Hi,

Ok, you say combining css. But then you have the reset.css. Does it make sence to put the
code from reset.css on top of the whole stylesheet?

Posted by: Paradise at January 24, 2008 11:06 AM

This is great information for someone that is getting ready to graduate with a degree in Web Technologies. I've designed a few sites for class projects but nothing major. You've done the testing and any information to help make sites faster is important. All the tips and suggestions are worth looking into.

Posted by: Ring at February 24, 2008 9:12 AM

Use vertical server scalability for best and low-cost performance using simple commodity hardware.

Remember to cache as much as possible.

http://www.thespeed.com/

Posted by: Neil at March 1, 2008 6:11 AM

There are 86 images on this page -- http://www.papergeni.co.za/index.htm -- yet it scores 100 on "Make Fewer HTTP Requests". How can this be?

Posted by: Nick at March 2, 2008 2:48 AM

What do you think about regular HTML table for layouts VS CSS-P. Do you think it will be worth to mention to the community since it will also increase performance. 1.- Because the HTML Code will be a lot less than regular HTML tables 2.- The CSS that will have the layout can also be on the cache especially if you keep the same layout on your site. Of course the CSS P code is a pain but it might be worth it.

Posted by: Edgar at March 26, 2008 10:25 PM

If you don't have any other tool for doing CSS sprites, I recommend SmartSprites [http://smartsprites.osinski.name/]. It's a tool that will automatically create CSS sprite images and modify your CSS rules to use them - all you have to do is code your CSS background images like normal, and add a few very simple annotations. I've only used it on a POC so far, and I'm sure you could come up with situations that break it. But even if you just use the generated code as a starting point, I recommend it highly!

Posted by: Josh J at April 2, 2008 12:27 PM

It is a pretty interesting issue. However, I am not yahoo - of course ;) The website with highest traffic is about 5.000 visitors a month. The others located at 100-300 visitors a month. Ok, I hope with experience bigger sites will come.
Anyway for better maintenance I have 5 stylesheets instead of 1 (my own css framework). What does this mean? Does it cost about 2 seconds, 5 seconds or 15 seconds?
And what's about requests to missing files (404)?

Posted by: Sebastian at April 10, 2008 10:42 AM

Post a comment

Comment Policy: We encourage comments and look forward to hearing from you. Please note that Yahoo! may, in our sole discretion, remove comments if they are off topic, inappropriate, or otherwise violate our Terms of Service.




Remember Me?


Copyright © 2008 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings