Improve Page Load Times

If visitors wait for a page to load, you’ve created a bad first impression. Your visitors want their question answered. So, they click on the first promising link or menu item. If the page doesn’t answer their question, they click the back-button. Unsurprisingly, the back-button is the most used browser feature. What’s more, these days Google slightly downgrades slow loading pages. Unfortunately, speeding up WordPress based websites need a little extra effort.

WebPagetest.org is a useful test. Fig 1 shows some results – achieved on  £16/year hosting.

Three factors determine the page-load-times, which are, in order of importance:

  1. The number of files your visitors download to see the web-page.
  2. The total size of the files;
  3. How quickly the web-host responds to your visitors’ requests for a file.

So, just reduce the number of files, reduce the total size of the files, and speed up the response of the web host.

I use the WordPress W3 Total Cache plug-in. It can work  well. I’ve reduced page load-times from over 10 seconds to around 1.5 seconds.  It’s usually possible to load pages from low-cost web-hosts in under 2 seconds.

There are plenty of posts recommending appropriate settings for W3 Total Cache. This article explains the effect of the settings and their options when using a shared host.

W3 Total Cache can be tricky.  I don’t think it’s the plug-in’s fault. W3 Total Cache writes to the .htaccess and wp-content files. Security plug-ins may not grant W3 Total Cache permission to write to these files. The best performance often requires Apache modules that low-cost web hosting services don’t provide. What’s more, it might not work with badly written plugins.

How to Reduce the number of files downloaded

WordPress has plugins for just about anything. Plugins to add features to web-pages,  often download additional CSS stylesheets, JavaScript files, and sometimes  a new font.  Add in your fonts, a few pictures and other images, and the visitor’s browser is  requesting  over 70 files. Each file request for a file must find first find your web-host,  wake up the server, which perhaps runs some code and then serves the file.  Even worse, the visitor’s browser only downloads between 2 and 8 files at the same time. The result is that new visitors wait over 10 seconds to see your page.  Yet you might think your webpages load quickly, because on previous visits you’ve already stored these files on your machine.

Fig 2 – Combine and Minify Files

Reduce the number of files by combing and compressing all the CSS stylesheets and all the JavaScript files. On shared hosting, I think, the page load is quicker if all stylesheets and JavaScript files download in two large files.  Using  W3 Total Cache, General Settings – Fig 2,   often it’s ok to set the minify mode to auto . However, test W3 Total Cache has found and combined all  files using tools.pingdom.com shown in Fig 3.

Fig 4 – Manual JavaScript Minification

If W3 Total Cache doesn’t combine all the JavaScript or CSS files, set minify to manual in General Settings. In the minify tab – Fig 4,  cut and paste  the URL of each JavaScript and CSS file into a list.  Note the minify checkbox means minify and combine.

Good minification removes the comments and the line breaks. Checking these boxes delivers a small gain.  However, poorly written JavaScript might not work if you remove the line breaks. Even worse, some plugins’s JavaScript might not handle minification.

It is probably not worth caching Google analytics JavaScript. Most browsers will have already have cached these files. Similarly, most browsers will have jQuery cached, so there is probably no need to serve it locally. I often cut and paste the Google analytics script into footer.php. However, WebPagetest.org assumes that the visitor’s browser cache is empty, and includes jQuery and Google analytics downloads. This is misleading, as most visitors’ browsers have these files.

Alas  if manually minifying JavaScript,  it’s usually easiest to include all the scripts in the /head, and use default blocking. This isn’t great practice.  JavaScripts can be either blocking or non-blocking:

  • Blocking JavaScripts must be downloaded, parsed and executed before the page  renders the HTML.  JavaScript is single threaded, which means  it performs one operation at a time.  The visitors browser is either downloading/executing JavaScript or rendering the page.  This isn’t good. You want the page to render  without waiting to download possibly unnecessary Javascript.
  • Non-blocking JavaScript  lets the page continue rendering, whilst the JavaScript downloads. This may cause problems if the JavaScript has, for instance,  an on-load trigger. The page loads, the on-load trigger fires, but the JavaScript isn’t downloaded, so the JavaScript doesn’t run.  However, if the JavaScript runs on events like mouse-over, which happen later when the visitor mouses around the page,  then all is well.

So the following non-blocking  options in Fig 4  may not work:

  • Non-blocking using JS  creates a “dynamic script node” . This script downloads the Javascript in a non-blocking way, so the page continues rendering, whilst the JavaScript downloads.  However, on some of my sites the JavaScript misses on-load events.
  • Async: These scripts execute as soon as the script is downloaded. However, the order of execution of the scripts isn’t guaranteed. Nevertheless, async scripts do execute before the load event. Of course, IE9 or below don’t support Async, and half my JavaScript is there so IE8 behaves.  Adding MSIE 6.0 MSIE 7.0 MSIE 8.0 MSIE 9.0 and Trident/4.0 Trident/5.0 (for testing) to Rejected User Agents in the minified setting is a solution. But then IE6.0 to IE9 won’t get minified content.
  • Defer: Waits for the HTML to finish loading before loading Javascript, so is slightly slower than Async. The JavaScript files should execute before the DOMContentLoaded event, and execute in the defined order. However,  it doesn’t really work in IE8 or IE9. 
  • Extsrc: Possibly refers to https://code.google.com/p/extsrcjs/ Apparently this works like Defer, is cross-platform, and good if JavaScript uses document.write.  However, for Google Maps, Twitter and Facebook buttons, asynsrc is recommended.
  • Asyncsrc: is like extsrc, but only works if the JavaScript doesn’t use document.write.

Fig 5 Manual CSS Minification

Just like manually minifying JavaScript files, add the URL of each css file.  There are some options:

  • Enable: enables minification and combining of CSS files.
  • Combine only: just combines the files, but doesn’t minify them.  I suspect that if both Combine only and Enable are checked, then you don’t get comment and line break removal.
  • Preserved comment removal: once the site is in production, there’s no need for the visitor to download your CSS comments
  • Line break removal: removes line breaks. – sometimes removing line breaks reveals CSS bugs.

@import processing, which imports multiple CSS files to create a single CSS file, has a couple of options:

  • Bubble:  This might refer to  a patch  that forces imported CSS to appear at the top of the CSS file.     About a year ago the plug-in author suggested bubble was unreliable.
  • Process: This option imports additional CSS files to create a single file.

Fig 6 HTML Minification

The other setting in the minify tab is HTML minification, which I enable. However, inline JS minification might break some scripts.

Add images to CSS or HTML

When I’m feeling obsessive, I base64 encode small images into the HTML and CSS. It saves a couple of calls to the server. It’s useful when you use a small png for a bullet, and small images in the header.  Web Coder Tools works ok. Similarly, including the odd  javascript file that needs to be within the /head within the HTML enables you to load the rest of the Javascript after the page renders.

Read more about Speeding up the Server’s response