Article

Web Site Optimization: 13 Simple Steps

Page: 1 2 3 4 Next

Option 2: mod_deflate for Apache 2.0

If your host runs Apache 2 you can use mod_deflate. Despite its name, mod_deflate also uses gzip compression. To configure mod_deflate, add the following directives to your .htaccess file:

AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/x-javascript application/json  
Header append Vary Accept-Encoding

Option 3: php.ini

Ideally we'd like Apache to handle the gzipping of content, but unfortunately some hosting providers might not allow it. If your hosting provider is one of these, it might allow you to use custom php.ini files. If you place a php.ini file in a directory, it overwrites PHP configuration settings for this directory and its subdirectories.

If you can't use Apache's mod_gzip or mod_deflate modules, you might still be able to compress your content using PHP. In order for this solution to work, you'll have to configure your web server so that all static HTML, JavaScript and CSS files are processed by PHP. This means more overhead for the server, but depending on your host, it might be your only option.

Add the following directives in your .htaccess file:

AddHandler application/x-httpd-php .css  
AddHandler application/x-httpd-php .html  
AddHandler application/x-httpd-php .js

This will ensure that PHP will process these (otherwise static) files. If it doesn't work, you can try renaming the files to have a .php extension (like example.js.php, and so on) to achieve the same result.

Now create a php.ini file in the same directory with the following content:

[PHP]  
zlib.output_compression = On  
zlib.output_compression_level = 6  
auto_prepend_file = "pre.php"  
short_open_tag = 0

This enables compression and sets the compression level to 6. Values for the compression level range from 0 to 9, where 9 is the best (and slowest) compression. The last line sets up a file called pre.php to be executed at the beginning of every script, as if you had typed <?php include "pre.php"; ?> at the top of every script. You'll need this file in order to set Content-Type headers, because some browsers might not like it when you send a CSS file that has, for example, a text/html content type header.

The short_open_tag setting is there to disable PHP short tags (<? ... ?>, as compared to <?php ... ?>). This is important because PHP will attempt to treat the <?xml tag in your HTML as PHP code.

Finally, create the file pre.php with the following content:

<?php  
 
$path = pathinfo($_SERVER['SCRIPT_NAME']);  
 
if ($path['extension'] == 'css')  {  
   header('Content-type: text/css');  
}  
 
if ($path['extension'] == 'js')  {  
   header('Content-type: application/x-javascript');  
}  
?>

This script will be executed before every file that has a .php, .html, .js or .css file extension. For HTML and PHP files, the default Content-Type text/html is okay, but for JavaScript and CSS files, we change it using PHP's header function.

Option 3 (Variant 2): PHP Settings in .htaccess

If your host allows you to set PHP settings in your .htaccess file, then you no longer need to use php.ini file to configure your compression settings. Instead, set the PHP setting in .htaccess using php_value (and php_flag).

Looking at the modified example from above, we would have the same pre.php file, no php.ini file, and a modified .htaccess that contained the following directives:

AddHandler application/x-httpd-php .css  
AddHandler application/x-httpd-php .html  
AddHandler application/x-httpd-php .js  
php_flag zlib.output_compression on  
php_value zlib.output_compression_level 6  
php_value auto_prepend_file "pre.php"  
php_flag short_open_tag off

Option 4: In-script Compression

If your hosting provider doesn't allow you to use php_value in your .htaccess file, nor do they allow you to use a custom php.ini file, your last resort is to modify the scripts to manually include the common pre.php file that will take care of the compression. This is the least-preferred option, but sometimes you may have no other alternative.

If this is your only option, you'll either be using an .htaccess file that contains the directives outlined in Option 3 above, or you'll have had to rename every .js and .css file (and .xml, .html, etc.) to have a .php extension. At the top of every file, add <?php include "pre.php"; ?> and create a file called pre.php that contains the following content:

<?php  
ob_start("ob_gzhandler");  
 
$path = pathinfo($_SERVER['SCRIPT_NAME']);  
 
if ($path['extension'] == 'css')  {  
   header('Content-type: text/css');  
}  
 
if ($path['extension'] == 'js')  {  
   header('Content-type: application/x-javascript');  
}  
?>

As I indicated, this is the least favorable option of all -- you should try Option 1 or 2 first, and if they don't work, consider Option 3 or 4, or a combination of both, depending on what your host allows.

Once you've established the degree of freedom your host permits, you can use the technique that you've employed to compress your static files to implement all of your Apache-related settings. For example, earlier I showed you how to set the Expires header. Well, guess what? Some hosts won't allow it. If you find yourself in this situation, you can use PHP's header function to set the Expires header from your PHP script.

To do so, you might add to your pre.php file something like this:

<?php  
header("Expires: Mon, 25 Dec 2017 05:00:00 GMT");  
?>

Disable ETags

Compared to the potential hassles that can be encountered when implementing the rule above, the application of this rule is very easy. You just need to add the following to your .htaccess file:

FileETags none

Note that this rule applies to sites that are in a server farm. If you're using a shared host, you could skip this step, but I recommend that you do it regardless because:

  • Hosts change their machines for internal purposes.
  • You may change hosts.
  • It's so simple.

Use CSS Sprites

Using a technique known as CSS sprites, you can combine several images into a single image, then use the CSS background-position property to show only the image you need. The technique is not intended for use with content images (those that appear in the HTML in <img /> tags, such as photos in a photo gallery), but is intended for use with ornamental and decorative images. These images will not affect the fundamental usability of the page, and are usually referenced from a style sheet in order to keep the HTML lean (Rule #0).

Let's look at an example. We'll take two images. The first is help.png; the second is rss.png. From these, we'll create a third image, sprite.png, which contains both images.

Combining two image files into a single image

The resulting image is often smaller in size than the sum of the two files' sizes, because the overhead associated with an image file is included only once. To display the first image, we'd use the following CSS rule:

#help {  
 background-image: url(sprite.png);  
 background-position: -8px -8px;  
 width: 16px;    
 height: 16px;  
}

To display the second image, we'd use the following rule:

#rss {  
 background-image: url(sprite.png);  
 background-position: -8px -40px;  
 width: 16px;    
 height: 16px;  
}

At first glance, this technique might look a bit strange, but it's really useful for decreasing the number of HTTP requests. The more images you combine this way, the better, because you're cutting the request overhead dramatically. For an example of this technique in use "in the wild", check out this image, used on Yahoo!'s homepage, or this one from Google's.

In order to produce sprite images quickly, without having to calculate pixel coordinates, feel free to use the CSS Sprites Generator tool that I've developed. And for more information about CSS sprites, be sure to read Dave Shea's article, titled CSS Sprites: Image Slicing's Kiss of Death.

Use Post-load Pre-loading and Inline Assets

If you're a responsible web developer, you're probably already adhering to the separation of concerns and using HTML for your content, CSS for presentation and JavaScript for behavior. While these distinct parts of a page should be kept in separate files at all times, for performance reasons you might sometimes consider breaking the rule on your index (home) page. The homepage should always be the fastest page on your site -- many first-time visitors may leave your site, no matter what content it contains, if they find the homepage slow to load.

When a visitor arrives at your homepage with an empty cache, the fastest way to deliver the page is to have only one request and no separate components. This means having scripts and styles inline (gasp)! It's actually possible to have inline images as well (although it's not supported in IE) but that's probably taking things too far. Apart from being semantically incorrect, using inline scripts and styles prevents those components from being cached, so a good strategy will be to load components in the background after the home page has loaded -- a technique with the slightly confusing name of post-load preloading. Let's see an example.

Let's suppose that the file containing your homepage is named home.html, that numerous other HTML files containing content are scattered throughout your site, and that all of these content pages use a JavaScript file, mystuff.js, of which only a small part is needed by the homepage.

Your strategy might be to take the part of the JavaScript that's used by the homepage out of mystuff.js and place it inline in home.html. Then, once home.html has completed loading, make a behind-the-scenes request to pre-load mystuff.js. This way, when the user hits one of your content pages, the JavaScript has already been delivered to the browser and cached.

Once again, this technique is used by some of the big boys: both Google and Yahoo! have inline scripts and styles on their homepages, and they also make use of post-load preloading. If you visit Google's homepage, it loads some HTML and one single image -- the logo. Then, once the home page has finished loading, there is a request to get the sprite image, which is not actually needed until the second page loads -- the one displaying the search results.

The Yahoo search page performs conditional pre-loading -- this page doesn't automatically load additional assets, but waits for the user to start typing in the search box. Once you've begun typing, it's almost guaranteed that you'll submit a search query. And when you do, you'll land on a search results page that contains some components that have already been cached for you.

Preloading an image can be done with a simple line of JavaScript:

new Image().src='image.png';

For preloading JavaScript files, use the JavaScript include_DOM technique and create a new <script> tag, like so:

var js = document.createElement('script');  
js.src = 'mysftuff.js';  
document.getElementsByTagName('head')[0].appendChild(js);

Here's the CSS version:

var css  = document.createElement('link');  
css.href = 'mystyle.css';  
css.rel  = 'stylesheet';  
document.getElementsByTagName('head')[0].appendChild(css);

In the first example, the image is requested but never used, so it doesn't affect the current page. In the second example, the script is added to the page, so as well as being downloaded, it will be parsed and executed. The same goes for the CSS -- it, too, will be applied to the page. If this is undesirable, you can still pre-load the assets using XMLHttpRequest.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links