Yahoo! Developer Network Blog

« Previous | Main | Next »


April 3, 2007

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

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 | Permalink

Bookmark this on Delicious

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

I have been writing about this on my blog at http://www.keralpatel.com and the useage of relative URLs instead of the absolute ones. The good thing is to check the total requests made per page load and trying to minimize it as much as possible.

Posted by: Keral Patel at June 4, 2008 10:01 PM

One thing not mentioned is memory preasure on a webserver. Most servers host 100's of websites & if yours is not one of the most popular then your code will not be in memory.
A popular method to get around this is to ping your web site. This will keep the site in the servers memory and keep your site responsive. I use a free service called Site Stalker (http://sitestalker.prestigedevgroup.com). They also collect stats on how often your site has outages and average response times.

-Will

Posted by: Will at June 10, 2008 6:47 PM

Latest version of SmartOptimizer can embed images in external stylesheets.
It handles browsers that doesn't support inline images and sends them original content.

Get it from here:
http://farhadi.ir/works/smartoptimizer

Posted by: Ali Farhadi at June 13, 2008 9:53 AM

Andy, the point about reducing HTTP requests isn't about header size or bandwidth, it's mainly about round-trip time.
The time-consumer is not a bandwidth limit, but simply waiting for the packets to traverse the network and the response to be returned.

HTTP is largely latency-sensitive, rather than bandwidth-sensitive. HTTP would work well over a 56k line (ie; bandwidth of a dial-up modem) if the latency was more realistic than an actual modem (ie; a modem designed for low-latency, rather than performing compression). The main reason broadband makes web-browsing seem faster is not because of increased bandwidth (check peak bandwidth usage for plain-text using wireshark), it's because DSL equipment is designed for low-latency, rather than attempting compression.

Posted by: Lee Carré at August 2, 2008 4:33 PM

We have a software component in Beta that implements a lot of these rules.
The RPO (runtime page optimizer):
-Combines JS, CSS
-Converts images to CSS sprites
Also - combining JS, CSS, Images means we can increase caching on client browsers, since server changes generate a new set of combined resources

This is done at runtime, so it means you don't have to make any development changes.
You can download the beta from www.getrpo.com (currently only for ASP.NET / SharePoint)

Ed Robinson
Chief Executive Officer
ActionThis
ed.robinson@actionthis.com

Posted by: Ed Robinson at August 21, 2008 2:47 AM

Please go to http://www.enginesdesktop.com/ed/compressHTML.aspx
it can compress whole site.

Posted by: alex c at October 15, 2008 1:23 PM

My host doesn't has mod_expires installed nor accept to do so. What can be the cause? And what other solution I have for expires?

Posted by: jose at March 22, 2009 9:37 AM

Good article. This helps me and i’m interested to minimize HTTP requests in my website too. Keep on your great work and help others. Thanx.

Posted by: Hemu at July 2, 2009 3:05 AM

It is beyond me why no resource bundling (by archiving them in files) has yet to be implemented in HTML.

See http://mindtrickle.wordpress.com/2009/07/03/packaging-resources-in-html-files/

Thoughts?

Posted by: Yaron Golan at July 3, 2009 2:36 AM

I am trying to reduce the number of http request on my works web site. As many people know there are always clashes between those that maintain things and those that want to make the site load faster.

When I use firebug it seems to take a long time to fetch outside js files. I was wondering what people thought if I used a server side scripting language to grab all the content from these sites then spit them out on the page. In between script tags.

I know this will add additional work on our server. This would decrease http request for the user and it would also reduce these ridiculous waiting times. Sometimes these outside script can take 1 to 2 seconds each (granted my work computer is pretty slow).

We are using a windows server 2008, Would the server "cache" these files much like a browser would then just check to see if the files changed? I am guess no, but maybe I am wrong.

I wish we didn't need these other outside scripts but I have put the ones I can onto the server. Some of the scripts need to stay on 3rd parties site. The marketing team wants needs theses scripts for tracking and other such things.

Posted by: John at December 5, 2009 8:12 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. Fields marked with asterisk '*' are required.

Remember Me?

Subscribe

YDN Blog: Get Yahoo! Developer Network Blog on your personalized My Yahoo! home page.

Add To My RSS Feed

YDN Link Blog: Get Yahoo! Developer Network Linkblog on your personalized My Yahoo! home page.

Add To My RSS Feed

Recent Readers

Copyright © 2010 Yahoo! Inc. All rights reserved. Copyright | Privacy Policy

Help us continue to improve the Yahoo! Developer Network: Send Your Suggestions