Article
Web Site Optimization: 13 Simple Steps
JavaScript Optimizations
Before diving into the JavaScript code and micro-optimizing every function and every loop, let's first look at what big-picture items we can tackle easily that might have a significant impact on a site's performance. Here are some guidelines for improving the impact that JavaScript files have on your site's performance:
- Merge
.jsfiles. - Minify or obfuscate scripts.
- Place scripts at the bottom of the page.
- Remove duplicates.
Merge .js Files
As per the basic rules, you should aim for your JavaScripts to make as few requests as possible; ideally, this also means that you should have only one .js file. This task is as simple as taking all .js script files and placing them into a single file.
While a single-file approach is recommended in most cases, sometimes you may derive some benefit from having two scripts -- one for the functionality that's needed as soon as the page loads, and another for the functionality that can wait for the page to load first. Another situation in which two files might be desirable is when your site makes use of a piece of functionality across multiple pages -- the shared scripts could be stored in one file (and thus cached from page to page), and the scripts specific to that one page could be stored in the second file.
Minify or Obfuscate Scripts
Now that you've merged your scripts, you can go ahead and minify or obfuscate them. Minifying means removing everything that's not necessary -- such as comments and whitespace. Obfuscating goes one step further and involves renaming and rearranging functions and variables so that their names are shorter, making the script very difficult to read. Obfuscation is often used as a way of keeping JavaScript source a secret, although if your script is available on the Web, it can never be 100% secret. Read more about minification and obfuscation in Douglas Crockford's helpful article on the topic.
In general, if you gzip the JavaScript, you'll already have made a huge gain in file size, and you'll only obtain a small additional benefit by minifying and/or obfuscating the script. On average, gzipping alone can result in savings of 75-80%, while gzipping and minifying can give you savings of 80-90%. Also, when you're changing your code to minify or obfuscate, there's a risk that you may introduce bugs. If you're not overly worried about someone stealing your code, you can probably forget obfuscation and just merge and minify, or even just merge your scripts only (but always gzip them!).
An excellent tool for JavaScript minification is JSMin and it also has a PHP port, among others. One obfuscation tool is Packer -- a free online tool that, incidentally, is used by jQuery.
Changing your code in order to merge and minify should become an extra, separate step in the process of developing your site. During development, you should use as many .js files as you see fit, and then when the site is ready to go live, substitute your "normal" scripts with the merged and minified version. You could even develop a tool to do this for you. Below, I've included an example of a small utility that does just this. It's a command-line script that uses the PHP port of JSMin:
<?php
include 'jsmin.php';
array_shift($argv);
foreach ($argv AS $file) {
echo '/* ', $file, ' */';
echo JSMin::minify(file_get_contents($file)), "\n";
}
?>
Really simple, isn't it? You can save it as compress.php and run it as follows:
$ php compress.php source1.js source2.js source3.js > result.js
This will combine and minify the files source1.js, source2.js, and source3.js into one file, called result.js.
The script above is useful when you merge and minify as a step in the site deployment process. Another, lazier option is to do the same on the fly -- check out Ed Eliot's blog post, and this blog post by SitePoint's Paul Annesley for some ideas.
Many third-party JavaScript libraries are provided in their uncompressed form as well as in a minified version. You can therefore download and use the minified versions provided by the library's creator, and then only worry about your own scripts. Something to keep in mind is the licensing of any third-party library that you use. Even though you might have combined and minified all of your scripts, you should still retain the copyright notices of each library alongside the code.
Place Scripts at the Bottom of the Page
The third rule of thumb to follow regarding JavaScript optimization is that the script should be placed at the bottom of the page, as close to the ending </body> tag as possible. The reason? Well, due to the nature of the scripts (they could potentially change anything on a page), browsers block all downloads when they encounters a <script> tag. So until a script is downloaded and parsed, no other downloads will be initiated.
Placing the script at the bottom is a way to avoid this negative blocking effect. Another reason to have as few <script> tags as possible is that the browser initiates its JavaScript parsing engine for every script it encounters. This can be expensive, and therefore parsing should ideally only occur once per page.
Remove Duplicates
Another guideline regarding JavaScript is to avoid including the same script twice. It may sound like strange advice (why would you ever do this?) but it happens: if, for example, a large site used multiple server-side includes that included JavaScript files, it's conceivable that two of these might double up. The duplicate script would cause the browser's parsing engine to be started twice and possibly (in some IE versions) even request the file for the second time. Duplicate scripts might also be an issue when you're using third party libraries. Let's suppose you had a carousel widget and a photo gallery widget that you downloaded from different sites, and they both used jQuery. In this case you'd want to make sure that you didn't include jQuery twice by mistake. Also, if you use YUI, make sure you don't include a library twice by including, for example, the DOM utility (dom-min.js), the Event utility (event-min.js) and the utilities.js library, which contains both DOM and Event.
CSS Optimizations
Merge and Minify
For your CSS files you can follow the guidelines we discussed for JavaScripts: minify and merge all style sheets into a single file to minimize download size and the number of HTTP requests taking place. Merging all files into one is a trivial task, but the job of minification may be a bit harder, especially if you're using CSS hacks to target specific browsers -- since some hacks exploit parsing bugs in the browsers, they might also trick your minifier utility.
You may decide not to go through the hassle of minifying style sheets (and the associated re-testing after minification). After all, if you decide to serve the merged and gzipped style sheet, that's already a pretty good optimization.
If you do decide to minify CSS, apart from the option of minifying manually (simply removing comments and whitespace), you can use some of the available tools, such as CSSTidy, PEAR's HTML_CSS library (http://pear.php.net/package/HTML_CSS/), or SitePoint's own Dust-me Selectors Firefox plugin.
Place Styles at the Top of the Page
Your single, gzipped (and optionally minified) style sheet is best placed at the beginning of the HTML file, in the <head> section -- which is where you'd usually put it anyway. The reason is that most browsers (Opera is an exception) won't render anything on the page until the all the style sheets are duly downloaded and parsed. Additionally, none of the images referenced from the CSS will be downloaded unless the CSS parsing is complete. So it's better to include the CSS as early on the page as possible.
You might think about distributing images across different domains, though. Images linked from the CSS won't be downloaded until later, so in the meantime, your page can use the available download window to request content images from the domain that hosts the CSS images and is temporarily "idle".
Ban Expressions
IE allows JavaScript expressions in CSS, like this one:
#content {
left: expression(document.body.offsetWidth)
}
You should avoid JavaScript expressions for a number of reasons. First of all, they're not supported by all browsers. They also harm the "separation of concerns". And, when it comes to performance, expressions are bad because they're recalculated every time the page is rendered or resized, or simply when you roll your mouse over the page. There are ways to make expressions less expensive -- you can cache values after they're initially calculated, but you're probably better off simply to avoid them.
Tools for Performance Optimization
A number of tools can help you in your performance optimization quest. Most importantly, you'd want to monitor what's happening when the page is loaded, so that you can make informed decisions. Try these utilities:
- Firebug's Net panel for Firefox, at http://www.getfirebug.com
- YSlow, Yahoo!'s performance extension to Firebug, at http://developer.yahoo.com/yslow/
- LiveHTTP Headers for Firefox, at http://livehttpheaders.mozdev.org/
- Fiddler -- for IE, but also a general-purpose packet sniffer, at http://www.fiddlertool.com/fiddler/
- HTTPWatch for IE (commercial, free version), at http://www.httpwatch.com/
- Web Inspector for Safari, at http://webkit.org/blog/?p=41
Summary
Whew! If you've made it this far, you now know quite a lot about how to approach a site optimization project (and more importantly, how to build your next web site with performance in mind). Remember the general rule of thumb that, when it comes to optimization, you should concentrate on the items with the biggest impact, as opposed to "micro-optimizing".
You may choose not to implement all the recommendations discussed above, but you can still make quite a difference by focusing on the really low-hanging fruit, such as:
- making fewer HTTP requests by combining components -- JavaScript files, style sheets and images (by using CSS Sprites)
- serving all textual content, including HTML, scripts, styles, XML, JSON, and plain text, in a gzipped format
- minifying and placing scripts at the bottom, and style sheets at the top of your files
- using separate cookie-free domains for your components
Good luck with your optimization efforts -- it's very rewarding when you see the results!