Website Performance Tweaks
In the last six months I became more aware of techniques for optimizing website performance. I learned about memory leaks and JavaScript performance, but what impressed me most was Nate Koechley’s presentation about large scale website performance issues in “Yahoo! vs. Yahoo!” at the @media conference 2006. In the meantime there have been more blog posts about particular aspects of performance optimization, and I’d like to sum them up:
Parsing JavaScript freezes the browser. Therefore put CSS in the head
and JavaScript near to the </body>
so that it is parsed when the page has been rendered.
The arch enemy of performance are HTTP requests. Many browsers still can’t handle more than two or four requests at a time. Keep the number of files down, your website will be faster.
There are several techniques with the aim to reduce the number of files:
“
A single large file is fastest.
” (Nate Koechley) That’s why Yahoo! apparently has such an amount of inline CSS. They found out browser caching is not as effective as they thought, in particular not on a user’s start page. So they deliver “inline” CSS. Actually writing inline CSS is a maintenance nightmare, but delivering CSS content inline doesn’t mean the files can’t have separate lives on the server: concatenate the files with a server side technique of your choice.Update: A couple of months later Nate explained that further: when your page is likely to be a user’s start page, caching plays a minor role, thus “inline” CSS is faster. Otherwise use external files, aggregate them, and make sure they are cached (see below).
Enforce caching. Another IE bug prevents image caching. Add the following to your
.htaccess
,httpd.conf
orvhost.conf
settings:<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 day"
ExpiresByType image/jpeg "access plus 1 day"
ExpiresByType image/gif "access plus 1 day"
ExpiresByType image/png "access plus 1 day"
</IfModule>
Reduce the number of background images with techniques like CSS Sprites or Sliding Doors. Instead of four images of rounded corners you only need one and get the mouseover state for free! The green download button on mozilla.com is based on that technique. And Yahoo! uses CSS Sprites to combine a huge number of icons.
Please note this approach is only for decorational background images that degrade gracefully.
It’s not forBe careful when you use it for foreground images. And if text comes as a graphical representation, it can become inaccessible for screen reader users, zoom readers, or people with stylesheets switched off. Use real text instead.img
elements.Also note changing the
background-position
causes IE6 to flicker, related to the caching bug above. To avoid it, simply add the following:<script type="text/javascript">
try { document.execCommand( "BackgroundImageCache", false, true); } catch(e) {};
</script>
Aggregate files. Ed Eliot wrote a nice script to merge JavaScript or CSS files, bonus respect for the advanced versioning and caching features.
But remember the cases when it doesn’t make sense to merge CSS files: your IE bugfixes still belong in conditional comments. If you use the
@import
rule to filter antique browsers from getting advanced styles, you can’t drop it. And if you want to merge stylesheets for different media (e.g. print), make sure the code is enclosed in something like@media print {
/* style sheet for print goes here */
}
In an updated version Ed added JSMin to strip comments and excess whitespace. JSMin works like a charm for JavaScript files. But it cuts a few space characters too much so that the syntax of CSS selectors changes
therefore for now I have abandoned the idea to compress them too. See Jens Meiert’s comment below for a recommendation to minimize CSS.His original code requires the C version of JSMin with PHP
safe_mode
turned off. If you prefer a pure PHP version, get the PHP version of JSMin and my adapted version of the script.
I’m still in awe how fast one of my own websites became! Thanks to the guys at Yahoo! for the inspiration and for most of the research this article is based upon. Even JSMin was written by an employee of Yahoo! Speaking about Yahoo! employees: Chris, I hope there are still enough topics for your Vitamin article. I wanted to write about performance anyway, and to my surprise I read yesterday that you have similar plans. See ya in Paris.
Darn, many overlaps there, especially pimping Ed’s script
But hey, it is no rocket science anyways.
How would JSMin compare to a dedicated JS compressor like Andrea Giammarchi’s? The download page of mootools states that JS Compressor reduces file size by 50% at maximum compression level.
[...] Martin Kliehm hat in einem interessanten Beitrag einen Teil seiner Erkenntnisse über Webseitenoptimierung zusammengetragen. Ich finde, für fortgeschrittene Webentwickler und für Profis ist dieses Thema ein Muß und der Artikel ein wirklich guter Einstieg. Interessanterweise erscheinen immer mehr Artikel zu diesem Thema und gerade Yahoo! hat in seinem YUI-Blog ein paar interessante Beiträge dazu gehabt. Die beiden Artikel über den Cache fand ich sehr bemerkenswert. Und so manche Erkenntnis rüttelt mittlerweile an liebgewonnenem Best-Practice. Ich denke, wir haben in dieser Richtung noch einiges zu lernen. Viel Umdenken wird dafür vonnöten sein. [...]
Robert, I haven’t benchmarked JSMin against JS compressor. But I merged five JavaScript files with a total size of 28 KB into one compressed file with 18 KB. JSMin does not obfuscate or shorten variable names, it only strips comments and whitespace (which I prefer).
[…] Mit diesen Tips holt man das Beste aus seiner Website heraus: Website Performance Tweaks. […]
Minifying and obfuscating/shortening variable names are a different matter. The former is a good way of making a script shorter by getting rid of whitespace and comments. Given you use clean JS (semicolons at the line end and after closing braces of functions) it doesn’t affect functionality. Packing however changes variable and function names, which can result in your code breaking if you for example pack several includes separately.
Martin — a really nice post which pulls together lots of useful information really well. Oh, and thanks for pimping my script.
[...] Das hier ist auch für mich total neu: Martin Kliehm hat einen interessanten Beitrag zum Thema Webseitenoptimierung geschrieben. Ein Muss für Webentwickler und Webdesigner: Website Performance Tweaks [...]
[...] für Zwecke der Seitenoptimierung empfehlen sich noch diese, diese und diese Seite — seeehr interessant. [...]
Good points (except that inline styles are almost never advisable in terms of “philosophy” and maintenance […]) — we should be happy about everyone emphasizing performance in times of homepages with 500+ KB size and 30+ seconds load time via 56k (that’s far from gone anyways).
Concerning CSS compression, though, try Peter Bengtsson’s code compressor to manually compress style sheets. Little awkward but “robust.” And concerning CSS and multiple style sheets — I recently suspected “print” targeted style sheets to be fetched on document load (which also makes sense anyway) — and which surely supports the recommendation to use a single style sheet.
Jens, thanks for the useful links, I will check them out. Concerning the “inline” styles: although they appear inline, they are maintained as separate CSS files and automatically merged with the main document on the server side.
Yet again, manual semi-trackback: Load time, the UX factor: Facts and measures.
I think another good addition to speed up your website is apache2’s
moddeflate
. Now my commented mootools is 180kb. When using moddeflate and JSMin (php) it gets down to 18kb!. Offcourse while using a caching mechanism to prevent obfusticating the JS each time a user loads any page. Same counts for css.SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI .(?:exe|t?gz|zip|bz2|sit|rar|swf|flv)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI .pdf$ no-gzip dont-vary
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch bMSIE !no-gzip !gzip-only-text/html
Hi Pim, thanks for the contribution! You are right, and there are even more techniques I wrote about in part 2 of this article. One of them concerns zipping content, though Nate Koechley stated that
gzip
is more efficient and better supported thandeflate
.Couldn’t you also introduce the concept of memcached in addition to the practices mentioned above? It would limit the the network calls on remote files, and could retrieve data much faster. This solution is obviously more server side, like gzip of deflate.
[…] Cod optimizat — toate spatiile din codul HTML care nu sunt necesare sunt eliminate, la fel si în fisierele CSS rezultând o dimensiune minima. De asemenea si codul PHP, din spatele website-ului este gândit în asa fel încât sa foloseasca cât mai eficient resursele serverului. […]
when trying to use your adapted version of the script with the PHP version of JSMin I am running into 2 problems:
1 – I need to change this code sCode = $jsMin->minify(); into $sCode = $jsMin->minify(); to get it to work to some degree
2 – then the source code in the browser would say something about Warning: filemtime() [function.filemtime]: stat failed for /home/bla/bla/bla/somejavascript.js in /home/home/bla/bla/bla/combine.php on line 107
line 107 in your script is this line in my file: $aLastModifieds[] = filemtime(“$sDocRoot/$sFile”);
any help would be appriciated to help resolve this issue
thanks in advance ! Josef
Thanks, though I found this late (rather I started looking for such articles really recently), after reading this and a lot of other blogs and slides, I thought about how to cook up a javascript aggregate plugin for wordpress. The out come is wp-jsmin. Though this is in its infancy, it is being used at PHP Trivandrum just as a test base.