By Steve Souders
Book Price: $29.99 USD
£18.50 GBP
PDF Price: $23.99
Cover | Table of Contents | Forum | Colophon
html, is the initial request for the HTML document. The browser parses the HTML and starts downloading the components in the page. In this case, the browser's cache was empty, so all of the components had to be downloaded. The HTML document is only 5% of the total response time. The user spends most of the other 95% waiting for the components to download; she also spends a small amount of time waiting for HTML, scripts, and stylesheets to be parsed, as shown by the blank gaps between downloads.
html, is the initial request for the HTML document. The browser parses the HTML and starts downloading the components in the page. In this case, the browser's cache was empty, so all of the components had to be downloaded. The HTML document is only 5% of the total response time. The user spends most of the other 95% waiting for the components to download; she also spends a small amount of time waiting for HTML, scripts, and stylesheets to be parsed, as shown by the blank gaps between downloads.
Empty cache | Primed cache | |
|---|---|---|
AOL | 6% | 14% |
Amazon | 18% | 14% |
CNN | 19% | 8% |
eBay | 2% | 8% |
Google | 14% | 36% |
MSN | 3% | 5% |
MySpace | 4% | 14% |
Wikipedia | 20% | 12% |
Yahoo! | 5% | 12% |
YouTube | 3% | 5% |
GET /us.js.yimg.com/lib/common/utils/2/yahoo_2.0.0-b2.js HTTP/1.1 Host: us.js2.yimg.com User-Agent: Mozilla/5.0 (...) Gecko/20061206 Firefox/1.5.0.9 HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Wed, 22 Feb 2006 04:15:54 GMT Content-Length: 355 var YAHOO=...
Accept-Encoding header. Servers identify compressed responses using the Content-Encoding header.GET /us.js.yimg.com/lib/common/utils/2/yahoo_2.0.0-b2.js HTTP/1.1 Host: us.js2.yimg.com User-Agent: Mozilla/5.0 (...) Gecko/20061206 Firefox/1.5.0.9 Accept-Encoding: gzip,deflate HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Wed, 22 Feb 2006 04:15:54 GMT Content-Length: 255 Content-Encoding: gzip ^_\;213^H^@^@^@^@^@^@^Cl\217\315j\3030^P\204_E\361IJ...
Accept-Encoding header. Servers identify compressed responses using the Content-Encoding header.GET /us.js.yimg.com/lib/common/utils/2/yahoo_2.0.0-b2.js HTTP/1.1 Host: us.js2.yimg.com User-Agent: Mozilla/5.0 (...) Gecko/20061206 Firefox/1.5.0.9 Accept-Encoding: gzip,deflate HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Wed, 22 Feb 2006 04:15:54 GMT Content-Length: 255 Content-Encoding: gzip ^_\;213^H^@^@^@^@^@^@^Cl\217\315j\3030^P\204_E\361IJ...
Vary and Cache-Control headers are also discussed.Last-Modified header in the response (refer to the previous sample responses). It uses the If-Modified-Since header to send the last modified date back to the server. The browser is essentially saying, "I have a version of this resource with the following last modified date. May I just use it?"GET /us.js.yimg.com/lib/common/utils/2/yahoo_2.0.0-b2.js HTTP/1.1 Host: us.js2.yimg.com User-Agent: Mozilla/5.0 (...) Gecko/20061206 Firefox/1.5.0.9 Accept-Encoding: gzip,deflate If-Modified-Since: Wed, 22 Feb 2006 04:15:54 GMT
HTTP/1.1 304 Not Modified Content-Type: application/x-javascript Last-Modified: Wed, 22 Feb 2006 04:15:54 GM
ETag and If-None-Match headers are another way to make conditional GET requests. Both approaches are discussed in .Expires header eliminates the need to check with the server by making it clear whether the browser can use its cached copy of a component.HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Wed, 22 Feb 2006 04:15:54 GMT Expires: Wed, 05 Oct 2016 19:16:20 GMT
Expires header in the response, it saves the expiration date with the component in its cache. As long as the component hasn't expired, the browser uses the cached version and avoids making any HTTP requests. talks about the Expires and Cache-Control headers in more detail.Connection header to indicate Keep-Alive support. The Connection header looks the same in the server's response.GET /us.js.yimg.com/lib/common/utils/2/yahoo_2.0.0-b2.js HTTP/1.1 Host: us.js2.yimg.com User-Agent: Mozilla/5.0 (...) Gecko/20061206 Firefox/1.5.0.9 Accept-Encoding: gzip,deflate Connection: keep-alive HTTP/1.1 200 OK Content-Type: application/x-javascript Last-Modified: Wed, 22 Feb 2006 04:15:54 GMT Connection: keep-alive
Connection: close header. Technically, the Connection: keep-alive header is not required in HTTP/1.1, but most browsers and servers still include it.
MAP tag. The HTML for converting the navbar in to an image map shows how the MAP tag is used:<img usemap="#map1" border=0 src="/images/imagemap.gif"> <map name="map1"> <area shape="rect" coords="0,0,31,31" href="home.html" title="Home"> <area shape="rect" coords="36,0,66,31" href="gifts.html" title="Gifts"> <area shape="rect" coords="71,0,101,31" href="cart.html" title="Cart"> <area shape="rect" coords="106,0,136,31" href="settings.html" title="Settings"> <area shape="rect" coords="141,0,171,31" href="help.html" title="Help"> </map>
SPAN or DIV. The HTML element is positioned over the desired part of the background image using the CSS background-position property. For example, you can use the "My" icon for an element's background image as follows:
<div style="background-image: url('a_lot_of_sprites.gif');
background-position: −260px −90px;
width: 26px; height: 24px;">
</div>
DIV named navbar. Each link is wrapped around a SPAN that uses a single background image, spritebg.gif, as defined in the #navbar span rule. Each SPAN has a different class that specifies the offset into the CSS sprite using the background-position property:
<style>
#navbar span {
width:31px;
height:31px;
display:inline;
float:left;
background-image:url(/images/spritebg.gif);
}
.home { background-position:0 0; margin-right:4px; margin-left: 4px;}
.gifts { background-position:-32px 0; margin-right:4px;}
.cart { background-position:-64px 0; margin-right:4px;}
.settings { background-position:-96px 0; margin-right:4px;}
.help { background-position:-128px 0; margin-right:0px;}
</style>
<div id="navbar" style="background-color: #F4F5EB; border: 2px ridge #333; width:
180px; height: 32px; padding: 4px 0 4px 0;">
<a href="javascript:alert('Home')"><span class="home"></span></a>
<a href="javascript:alert('Gifts')"><span class="gifts"></span></a>
<a href="javascript:alert('Cart')"><span class="cart"></span></a>
<a href="javascript:alert('Settings')"><span class="settings"></span></a>
<a href="javascript:alert('Help')"><span class="help"></span></a>
</div>
data: URL scheme. Although this approach is not currently supported in Internet Explorer, the savings it can bring to other browsers makes it worth mentioning.http: scheme. Other schemes include the familiar ftp:, file:, and mailto: schemes. But there are many more schemes, such as smtp:, pop:, dns:, whois:, finger:, daytime:, news:, and urn:. Some of these are officially registered; others are accepted because of their common usage.data: URL scheme was first proposed in 1995. The specification (http://tools.ietf.org/html/rfc2397) says it "allows inclusion of small data items as 'immediate' data." The data is in the URL itself following this format:data:[<mediatype>][;base64],<data>
<IMG ALT="Red Star" SRC="data:image/gif;base64,R0lGODlhDAAMALMLAPN8ffBiYvWW lvrKy/FvcPewsO9VVfajo+w6O/zl5estLv/8/AAAAAAAAAAAAAAAACH5BAEA AAsALAAAAAAMAAwAAAQzcElZyryTEHyTUgknHd9xGV+qKsYirKkwDYiKDBia tt2H1KBLQRFIJAIKywRgmhwAIlEEADs=">
data: used only for inline images, but it can be used anywhere a URL is specified, including SCRIPT and A tags.data: URL scheme is that it's not supported in Internet Explorer (up to and including version 7). Another drawback is its possible size limitations, but Firefox 1.5 accepts inline images up to 100K. The base64 encoding increases the size of images, so the total size downloaded is increased.data: URLs are embedded in the page, they won't be cached across different pages. You might not want to inline your company logo, because it would make every page grow by the encoded size of the logo. A clever way around this is to use CSS and inline the image as a background. Placing this CSS rule in an external stylesheet means that the data is cached inside the stylesheet. In the following example, the background images used for each link in the navbar are implemented using inline images in an external stylesheet.Web site | Scripts | Stylesheets |
|---|---|---|
3 | 1 | |
18 | 1 | |
11 | 2 | |
7 | 2 | |
1 | 1 | |
9 | 1 | |
2 | 2 | |
3 | 1 | |
4 | 1 | |
7 | 3 |
Only 10–20% of the end user response time is spent downloading the HTML document. The other 80–90% is spent downloading all the components in the page.
Web site | CDN |
|---|---|
Akamai | |
Akamai | |
Akamai, Mirror Image | |
SAVVIS | |
Akamai, Limelight | |
Akamai | |
Expires header, you make those components cacheable. This avoids unnecessary HTTP requests on subsequent page views. A future Expires header is most often used with images, but it should be used on all components, including scripts, stylesheets, and Flash. Most top web sites are not currently doing this. In this chapter, I point out these sites and show why their pages aren't as fast as they could be. Adding a future Expires header incurs some additional development costs, as described in the section "."Expires header to tell the web client that it can use the current copy of a component until the specified time. The HTTP specification summarizes this header as "the date/time after which the response is considered stale." It is sent in the HTTP response.Expires: Thu, 15 Apr 2010 20:00:00 GMT
Expires header and HTTP.ExpiresExpires header to tell the web client that it can use the current copy of a component until the specified time. The HTTP specification summarizes this header as "the date/time after which the response is considered stale." It is sent in the HTTP response.Expires: Thu, 15 Apr 2010 20:00:00 GMT
Expires header and HTTP.Expires header. The Cache-Control header was introduced in HTTP/1.1 to overcome limitations with the Expires header. Because the Expires header uses a specific date, it has stricter clock synchronization requirements between server and client. Also, the expiration dates have to be constantly checked, and when that future date finally arrives, a new date must be provided in the server's configuration.Cache-Control uses the max-age directive to specify how long a component is cached. It defines the freshness window in seconds. If less than max-age seconds have passed since the component was requested, the browser will use the cached version, thus avoiding an additional HTTP request. A far future max-age header might set the freshness window 10 years in the future.Cache-Control: max-age=315360000
Cache-Control with max-age overcomes the limitations of Expires, but you still might want an Expires header for browsers that don't support HTTP/1.1 (even though this is probably less than 1% of your traffic). You could specify both response headers, Expires and Cache-Control max-age. If both are present, the HTTP specification dictates that the max-age directive will override the Expires header. However, if you're conscientious, you'll still worry about the clock synchronization and configuration maintenance issues with Expires.mod_expires Apache module (http://httpd.apache.org/docs/2.0/mod/mod_expires.html) lets you use an Expires header that sets the date in a relative fashion similar to max-age. This is done via the ExpiresDefault directive. In this example, the expiration date for images, scripts, and stylesheets is set 10 years from the time of the request:<FilesMatch "\.(gif|jpg|js|css)$"> ExpiresDefault "access plus 10 years" </FilesMatch>
Expires header and a Cache-Control max-age header in the response.Expires: Sun, 16 Oct 2016 05:43:02 GMT Cache-Control: max-age=315360000
Expires header affects page views only after a user has already visited your site. It has no effect on the number of HTTP requests when a user visits your site for the first time and the browser's cache is empty. Therefore, the impact of this performance improvement depends on how often users hit your pages with a primed cache. It's likely that a majority of your traffic comes from users with a primed cache. Making your components cacheable improves the response time for these users.Expires header on images is fairly common, but this best practice should not be limited to images. A far future Expires header should be included on any component that changes infrequently, including scripts, stylesheets, and Flash components. Typically, an HTML document won't have a future Expires header because it contains dynamic content that is updated on each user request.Expires header, and subsequent page views would make just a single HTTP request for the HTML document. When all of the document's components are read from the browser's cache, the response time is cut by 50% or more.Expires or a Cache-Control max-age header set at least 30 days in the future. As shown in , the news isn't good. Three types of components are tallied: images, stylesheets, and scripts. shows the number of components that are cacheable for at least 30 days out of the total number of components of each type. Let's see to what extent these sites employ the practice of making their components cacheable:Web site | Images | Stylesheets | Scripts |
|---|