I’m a big fan of Google Tech Talks. Recently, I caught a particularly interesting one from Steve Souders called Life’s Too Short – Write Fast Code. Steve Souders used to work for Yahoo! as their chief web performance guru; he now does much the same at Google. The talk was a continuation of a previous lecture on a firebug extension that he wrote called YSlow. Suffice it to say, he knows what he’s talking about when it comes to high performance web sites. Anyway, it piqued my interest, so I decided to try to improve the performance of my own site. This article/tutorial and the next chronicle the changes I made and the results that I obtained.
YSlow’s 13 Rules to Improve Web Site Performance (rules 1-4)
YSlow grades web sites based on 13 different rules. Browse to your site, click on the YSlow icon in the lower right corner of Firefox, and click on the Performance tab. Here’s how one post on my site ranked before making any changes:
Clicking on any rule takes you to a page explaining it in more detail.
A quick note: the screenshot above was taken before I disabled Woopra, which is web analytics software similar to Google Analytics. I had tried it out a couple months ago and had simply forgotten that I had it enabled. Disabling Woopra improved my grades very slighty in a number of rules, but I don’t include that optimization in the main article because it’s technically a functional change to my site. As explained below, YSlow doesn’t make functional recommendations.
What follows are the changes that I made to my site, rule-by-rule.
1. Make fewer HTTP requests
This is one of the most important rules and it’s also one of the most difficult to implement. It’s worth mentioning at this point that YSlow’s general strategy isn’t to recommend changes that alter the actual content and functionality of a site, but instead suggest changes that will make the same content load faster. In other words, if you have a gallery with 20 images, the recommendation isn’t to cut the gallery down to 5 images. Consequently, Make fewer HTTP requests focuses on three components of web pages: javascript, stylesheets, and background images.
Expanding the rule will show counts of each component if they exceed YSlow’s thresolds:
In the case of my blog, the problem comes down to external javascript and CSS. To get a list of page components, click on the Components tab. They’re sorted by type so, it’s very easy to identify the problem files.
I can group these into 4 basic categories: Google Adsense, Google Analytics, reCAPTCHA, and WordPress plugins. Adsense has a particularly egregious number of external javascript files. Unfortunately, there’s nothing I can do about it as modifying the code is against Adsense policies. Analytics has just one javascript file and keeping that external is probably a good idea. Almost anyone who browses more than a handful of sites will have ga.js cached as Analytics use is pervasive. Similarly, there’s a good possibility that visitors will have the main reCAPTCHA javascript cached and the other code is dynamic so you don’t want to mess with it. Finally, there are the stylesheets from WordPress plugins.
Combining CSS into one file–especially when it’s all hosted on the same server–is a really good idea. In this case, I’m serving my main style.css file and two other stylesheets from the wp-recaptcha plugin and the Deko Boko plugin. I wrote a simple script to combine all of the files into one, like so:
#!/bin/sh cat style.css.original \ ../../plugins/wp-recaptcha/recaptcha.css \ ../../plugins/deko-boko-a-recaptcha-contact-form-plugin/display/dekoboko.css \ > style.css
I also modified both plugins to no longer include a link to their original stylesheets in the section of the page. Search the PHP files for references to the original stylesheets and comment those lines out.
Before moving on, it’s worth mentioning that you should use CSS sprites if at all possible. Many sites use tens of icons per page. Combining those tiny icons into one sprite is a huge performance boost.
2. Use a CDN
One persistent criticism of YSlow is that it focuses on performance improvements to major sites. I don’t really agree with that; in fact, nearly every rule applies equally to both small and large sites. Use a CDN is the exception. A CDN allows you to serve content to users from geographically close servers. It’s a decent performance improvement, but it’s also incredibly expensive.
3. Add an Expires header
What’s the fastest HTTP request? One that never takes place. The idea behind far future Expires headers is that you should allow permanent caching of any page component that won’t change or even that is unlikely to change very often. If it does need to be modified, you simply rename it. To accomplish this using Apache, enable mod_expires and add the following to the virtual host configuration or the main .htaccess:
ExpiresActive On ExpiresByType image/gif "access plus 10 years" ExpiresByType image/jpeg "access plus 10 years" ExpiresByType image/png "access plus 10 years" ExpiresByType text/css "access plus 10 years"
Warning: The preceding configuration means that any time you change an image or stylesheet served my Apache, you must rename it. If a browser or proxy server has the component cached, it will never check to see if its version is the same as the version on your server. For images, this is probably not an annoyance; changing an image usually means uploading a new version in which case it will have a different file name anyway. For stylesheets, this can be annoying if you don’t automate the process.
I solved the stylesheet problem with a script. In the same directory as style.css, I created a text file like so:
$ echo 0 > serial.txt
Next, I modified the script that combined the 3 original stylesheets I was using like so:
#!/bin/sh SERIAL_FILE=serial.txt OLD_SERIAL=`cat ${SERIAL_FILE}` SERIAL=$((${OLD_SERIAL} + 1)) cat style.css.original \ ../../plugins/wp-recaptcha/recaptcha.css \ ../../plugins/deko-boko-a-recaptcha-contact-form-plugin/display/dekoboko.css \ > style-${SERIAL}.css sed "s/REPLACE_WITH_SERIAL/${SERIAL}/g" < header.php.original > header.php rm -f style-${OLD_SERIAL}.css echo ${SERIAL} > ${SERIAL_FILE}
The script reads a number in from serial.txt, increments it, creates a new stylesheet with the number appended, and in this case modifies WordPress’ header.php to link to the new stylesheet. Every time I want a different style on my site, I modifiy style.css.original and run this script.
4. Gzip components
Everyone in every circumstance should enable mod_deflate. Way back in the early days of the web there were browsers that didn’t play well with gzip; they basically don’t exist anymore. In Apache, enable mod_deflate–it’s probably already enabled–and add the following to the virtual host configuration or the main .htacess:
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
Continued Soon
When I started writing this post, I didn’t realize how long it was going to be. Part two, which will include the other 9 easier-to-implement and less important rules, should be up within a few days. I’ll also include some before-and-after performance statistics.
Part two is now finished: Using YSlow to Optimize Web Site Performance Continued.
4 replies on “Using YSlow to Optimize Web Site Performance”
Regarding this in #3: “The preceding configuration means that any time you change an image or stylesheet served my Apache, you must rename it.”
I will agree to this with respect to images unless the change is merely a reduction of its footprint, such as when you use Photoshop to optimize the bits. In this case, it’s not worth it to rename the file.
That’s because you’re forcing everyone who has already using the image to download essentially the same one again, albeit smaller. It’s obviously faster to display the bigger image that’s cached than the smaller image that’s downloaded.
Re: #4, if you put the following after the deflates, it should prevent gzip’ing for browsers that can’t handle it:
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
Thanks. I’m using nginx now, but that might help someone else.
More on getting WPO thinking integrated throughtout the entire design and development process:
http://www.netmagazine.com/features/save-planet-through-sustainable-web-design