Improve your web site performance – tips & tricks to get a good YSlow rating

When YSlow was released to indicate how well a web site performed, there were a lot of people disappointed, and perplexed, by their own score. Overall, I think performance is underrated, so I thought I’d give you some short guidelines how to improve the performance of your web site.

YSlow, for those not familiar with it, is a tool based on the research done by Steve Souders (ex-Yahoo!, now Google) and the Yahoo! performance team, to help people improve web site performance and find common bottle-necks.

The rules and their values

In YSlow, there are 13 rules, which have different values in the overall score, that goes from 0 to 100 (the one rule that has fallen out from the original 14 rules in the High Performance Web Sites book is about AJAX and caching). These are, with respective point values (taken from Dissecting YSlow):

Value 11

Value 10

Value 5

Value 4

Value 3

Rule 1 – Make fewer HTTP requests (CSS Background images)

Value 2

Rule 7 – Avoid CSS expressions

What rules to care about

This is where it becomes a little bit more interesting. Most rules everyone agrees about, but there are some that has caused a little bit of a controversy in there. While YSlow: Yahoo’s Problems Are Not Your Problems goes into detail a little bit more, I would argue that the only rule I would definitely want to be optional, and turned off by default, is the Use a Content Delivery Network (CDN) one.

Basically, using a CDN is about having your static content spread out through servers across the world, to offer something as geographically close to your end user as possible, and to meet traffic spikes in the most prepared manner. The fine print here is that CDNs are extremely costly, and the need for one really only applies to enormously high-traffic web sites such as Google, Yahoo! etc.

To force this rule upon us mere mortals with less than one million visitors per day or so is pretty much a waste. CDNs are a good thing, no doubt, but since it only applies to a minority, it should be left out. This means that the best score you can get for a web site is 90/100, so start considering 90 to be top notch/high score.

Some other rules can discussed, but generally, all the rest of them are good ones.

Making improvements

The ones such as where to put your CSS and JavaScript files, minifying them and packing them together, avoiding redundant code and making files external are quite self-explanatory; so I’ll leave them out of the discussion here. Instead, I’d like to show you how to improve the other ones on an Apache server, version 2 (which is the most popular web server on the web); other alternatives are mentioned at the end of the post.

The bases for the following advice is that you have access to two files: httpd.conf, which is located in your Apache installation folder, and .htaccess, which is the root of your web site (if it’s not there, just create it).

How to Gzip compontents

Gzipping is the most effective way to compress files, and the way it works is that a web browser states to server that it accepts gzip when it makes a request, and the server then returns the content in a gzipped format. This means that what’s sent over the wire is much, much smaller, thus decreasing bandwidth usage and request time. After the web browser has received the file, it unpacks it and the file works in its original format.

Open httpd.conf and uncomment this line (for those new to this file, a hash mark (#) is used to comment out a line; just remove it to activate that line):

LoadModule deflate_module libexec/apache2/mod_deflate.so

Then you have two alternatives to choose what file types you want to compress. Typically, you’ll want to compress the HTML output, CSS, JavaScript, and any other text-based format. Add any of the alternatives below to the httpd.conf file.

Alternative 1

AddOutputFilterByType DEFLATE text/html text/plain text/css text/javascript
application/x-javascript

Overall, this approach works great, but I’ve had problems where specifically JavaScript files weren’t compressed.

Alternative 2

This approach is rather based on compressing everything, and then specify which file types to exclude from that. Typically, you don’t want to compress images and some other formats, since they are already so compressed to begin with.

SetOutputFilter DEFLATE
DeflateFilterNote ratio
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ \
    no-gzip dont-vary
SetEnvIfNoCase Request_URI \
    \.(?:exe|t?gz|zip|bz2|sit|rar)$ \
    no-gzip dont-vary
SetEnvIfNoCase Request_URI \.pdf$ no-gzip dont-vary

Covering up for web browsers which might fail

Naturally, there are web browser out there claiming to support gzip when talking to the server, but not living up to it in practice. Amongst these are Internet Explorer (shocker), at least up till version 6, so you can also add this to the file:

BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

An alternative way to Gzip

Chances are, your host maybe doesn’t allow you to edit the httpd.conf file, meaning you can’t rely on Apache to do this for you. However, I found another way to do it through Reducing Bandwidth Usage when Deploying Web Applications. The idea is to locally gzip your files(s), and then name them with a .gz.js or .gz.css extension, to get the web server and requesting web browsers to treat them as pre-gzipped files.

Open up the Terminal where your files are, and gzip them like this:

gzip -c originalFile > myDeployFile.gz.js

When it comes to the HTML content itself, many tools out there supports compressing it on its own (for you bloggers, WordPress has this under Options > Reading: “WordPress should compress articles (gzip) if browsers ask for them”).

How to configure ETags

ETags are HTTP headers, which identify when a file was changed. The basis is that a web browser will only get that file if the ETag has changed since the last request. There is a very simple way to tell Apache to add an ETag consisting of the file’s modified time and its file size.

Open up the .htaccess file, add this line, and you’re good to go:

FileETag MTime Size

How to add Expires headers

First, let me explain how requests for a file works:

  1. If the visitor has an empty cache (in regards to your content), it will fetch all necessary files from the server.
  2. If the visitor has your files in the web browser cache, it still has to send a conditional GET request to your server, to compare if the last modified time of the file in the web browser cache is the same as the file on the server. If not, it fetches a new version of the file in question.
  3. If a file has a future expires value set, it won’t even go to the server at all until that time has occurred, thus leading to completely eliminating that request.

Therefore, using expires headers are extremely efficient for static files in your web site. To do it, begin with opening up the httpd.conf file and enable the expires module:

LoadModule expires_module libexec/apache2/mod_expires.so

Then, open up the .htaccess file and add what file types you want to set expires header for, and how long that time should be:

Alternative 1

ExpiresActive On
ExpiresByType text/css "access plus 3 days"
ExpiresByType application/x-javascript "access plus 3 days"
ExpiresByType image/gif "access plus 3 days"
ExpiresByType image/png "access plus 3 days"
ExpiresByType image/jpeg "access plus 3 days"

Alternative 2

Another option can be to turn on expires header for everything:

ExpiresActive On
ExpiresDefault "access plus 3 days"

The value needed to get a good YSLow grade is to have expires headers set at least 48 hours into the future, but in practice, you need configure the values that suits your needs the best. Note: If you need to push out new files to the end user and overriding the existing web browser cache, you either have to change the actual file names, or adding a query string to the requests with a new value. For example, changing 19 in the query string below to, e.g. 20, would force the web browser to get a new version from the server.

<link rel=”stylesheet” href=”/css/base.css?19″ type=”text/css”>

We want proof that this works!

Curious and hungry for knowledge, I naturally had to try all this out to improve the end user experience for you, my dear readers. The result of implementing the above solutions are a YSlow ranking for Robert’s talk of (mostly) 80, and for the DOMAssistant web site, a value of 88.

Someone visiting Robert’s talk for the first time will get 30 HTTP requests, while a returning visitor will only have 6 HTTP requests. Quite an improvement, right? 🙂

The reasons for not getting 90 (top score unless you’re Donald Trump, remember?) is, for Robert’s talk, my Flickr images and a couple of statistics scripts. With the DOMAssistant web site, it’s only statistics script holding it back from being top notch.

Other environments

Internet Information Server (IIS)

Django, Apache, and Lighttpd

Also, if you want to read more about what I touched on above, I definitely recommend reading Tools for optimizing your website: Etag and Expire headers in Django, Apache, and Lighttpd.

Performance does matter

At the end of the day, I want you to get good web sites that are incredibly fast to load. Therefore, I sincerely hope you’ve learned something from this that will improve the future performance of the web sites you’ll be working on.

Good luck performing! 🙂

55 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *