bitstorm.org

Weblog by Edwin Martin about frontend webdevelopment and related topics

Faster websites with gzip compression

One of the best ways to improve the user experience of a website is to make sure it loads fast. In a test done by Mozilla, it also improves conversion. Research by Google also shows advantages.

One of the easiest ways to improve download speed is using gzip. Since many webbased files like html, css and javascript are text based, compressing them with gzip will result in more than 50% size reduction.

Older browsers had some problems with gzip, so site owners where a bit reluctant to use gzip. Currently, all modern browers (even IE with the right service pack applied) have no problem with using gzip.

Apache has a module called mod_deflate, which is easy to enable. For example:

AddOutputFilterByType DEFLATE text/html text/plain text/xml text/javascript text/css

Mod_deflate will compress the content on the fly for every request. On a high-performance site, that’s not really what you want. There are better ways.

Compressing static content

First you have to compress all text files. Typically, there are files ending with .html, .css, .js and .xml. When using Linux, make sure you have gzip installed. Don’t just gzip the files you want to compress, because the original file will be gone. Better is to do this:

gzip -nc myfile.css >  myfile.css.gz

Disadvantage is, you can’t do this with a bunch of files. I wrote a little script to fix this:

echo -n $@ | xargs -d ' ' -I '{}' sh -c "gzip -n -c {} > {}.gz"

Put it in a file, for example /usr/local/bin/zipit, make it executable: chmod +x /usr/local/bin/zipit and now you can use it to compress single files, but also files with wildcards. For example:

zipit *.js *.css

If you had lib.js and style.css, now you will also have the compressed versions: lib.js.gz and style.css.gz.

Warning: you have to be careful here: uploading a new .js- or .css-file won't work! You have to run zipit again, otherwise the .gz-file with the old content might be picked up.

In Windows, you can gzip your files in a batchfile. You can use the free 7-Zip to to that. For example:

"C:\Program Files\7-Zip\7z.exe" a -tgzip style.css.gz style.css

Zopfli

Update March 12th, 2013: the compression algorithm has been improved. It’s called zopfli. The nice thing is that the resulting file is still a valid gzip file and can be decompressed by the existing software. Decrompression doesn’t take any longer, too. The resulting file will be around 5% smaller than the best gzip algorithm. The time to compress can be hundred times slower, but since this article is about one time compression, it’s still worth the effort.

Download the Zopfli sources, run make and copy the resulting file to /usr/local/bin.

To run zopfli on multiple files, you don’t need a batch file, just run it like this:

zopfli -i1000 *.js *.css

Let Apache serve compressed content

There are several ways to let Apache serve the .gz-files. I prefer using mod_rewrite. I wrote the following configuration file to serve the gzipped files:

<FilesMatch "\.html\.gz$">
  ForceType text/html
  Header set Content-Encoding: gzip
</FilesMatch>

<FilesMatch "\.js\.gz$">
  ForceType text/javascript
  Header set Content-Encoding: gzip
</FilesMatch>

<FilesMatch "\.css\.gz$">
  ForceType text/css
  Header set Content-Encoding: gzip
</FilesMatch>

RewriteEngine On
ReWriteCond %{HTTP:accept-encoding} gzip
ReWriteCond %{REQUEST_FILENAME} !\.gz$
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME}.gz -f
RewriteRule ^(.+\.js|.+\.css|.+\.html)$ $1.gz [L]

It’s quite low-level and therefore very clear. The rewrite rules checks the browser supports gzip, then it makes sure it’s not already getting the .gz-file. As a last check it checks for the existance of the .gz-file. If that’s the case, the url is rewritten to have .gz at the end. The FilesMatch-directive makes sure the content-type is correct and adds “Content-Encoding: gzip” to the http-header, so the browser knows it’s gzipped content.

Gzip and PHP

Most server-side languages also support gzipped output. PHP has several ways to do that.

If you’re using ob_start to buffer the output, you can easily enable gzip-compression by using ob_gzhandler:

ob_start("ob_gzhandler");

A better way might be to enable gzip on all PHP-scripts. Just enable zlib.output_compression in your php.ini-file:

zlib.output_compression On

PHP has quite a lot of gzip-related functions. You can easily zip or unzip strings and work with gzipped files as they where normal files.

Check gzip is working

How can you be sure your content is compressed? Just open the Net-tab within Firebug and reload the page. Open the headers of the file you want to inspect. It will look similar to this:

Date                Mon, 10 May 2010 14:19:06 GMT
Server              Apache/2.2.4
Vary                accept-encoding
Last-Modified       Thu, 29 Apr 2010 09:23:59 GMT
Etag                "9043e7-856-afc129c0"
Accept-Ranges       bytes
Content-Length      2134
Cache-Control       max-age=172800 proxy-revalidate
Content-Encoding    gzip
Content-Type        text/html

When you see “Content-Encoding gzip” as in the example above, you’ll know it is compressed. Or use YSlow or Page Speed and look at the A’s you’ll get!