Website Optimisation Measures
-
Move Scripts to the Bottom of the Body
- Use
async
and defer
Script
Attributes
- Ensure the Site Works With JavaScript Off
- Provide Proper Fallbacks for Flash Content
- Clean Up the Head
- Styleheets First
- Add Height & Width on
<img>
Tags
- Optimise Images
-
Reduce HTTP-Requests
- Combine Print Stylesheet With Main Stylesheet:
- Combine Javascript Files:
- Use CSS Sprite Sheets:
- Use Base-64 Encoded Images:
- GZip What You Can
- Imitate Background Images With Colours
- Write / Output Cleanly Indented HTML
- Drop Internet Explorer 6 Support
- Do Not Block Browsers for ‘Compatibility’
Jens Mieret publishes a list
of general tips on optimising websites for in his opinion speed, simplicity, accessibility and user
friendliness.
This presents a lot of valuable information in a very simple way, and therefore as a good idea, it should be
stolen borrowed.
Here are, in my opinion, a number of key optimisation tips for your website:
Move Scripts to the Bottom of the Body
When the page loading hits a script tag—everything stops. Scripts have the right of way. A script can’t change
the DOM until the HTML has loaded, so more important things like stylesheets are held up loading a
script file that’s no actual use until the HTML has finished loading! Get your HTML structure and CSS to the user
as quick as you can. The browser will be able to render the page much quicker and then scripts can
be loaded, rather than leaving a blank page for the user to stare at whilst they wait for scripts to download.
⋮
<script src="js/main.js"></script>
</body>
Moving the script tags to just before the </body>
tag alone
will make your website noticeably snappier! However, doing this brings added responsibility. Because the page will
render before scripts have initialised, particularly quick clickers will be able to interact with your site before
your JavaScript is ready! This brings us on to the next tip:
Use async
and defer
Script Attributes
HTML5 provides two new
attributes for <script>
tags.
The async
attributes causes the script to be executed without the browser waiting for execution to
complete before continuing. This means that multiple scripts elements won’t block the browser from downloading
other resources and rendering.
<script async src="js/main.js"></script>
<img src="test.png" alt="HTML5 script async means that this image will be downloaded in parallel" />
(though, as noted earlier, your scripts should be at the bottom of the body anyway)
async
can be used when you need to load JavaScript libraries which do not modify the DOM
(async
scripts are run before the DOM is ready) and keep the rest of the page loading.
defer
causes the script to wait until the DOM is ready before executing. Use this for scripts that
intend to modify the document.
Browser support is weak at the moment, IE supports defer
(since v5.5!) and Firefox 3.5 supports
async
and defer
but it doesn’t hurt to add these to your script tags to future proof
as new browsers pick up support. Until then, there’s a whole
variety of ways you
can asynchronously load scripts to gain performance.
Ensure the Site Works With JavaScript Off
I cannot stress this enough, and how much it makes a positive difference—even when JavaScript is enabled! Firstly,
more and more people are now browsing with JavaScript switched off by default thanks to the security benefits and
flexibility provided by NoScript. It increases
browsing speed, frees up bandwidth, increases privacy by blocking all sorts of third party scripts, and helps
mitigate XSS attacks.
Just as your HTML and CSS should be separate, so should your JavaScript. If you
code your site to work without
AJAX first all your server-side events are done, you can just veneer the site with event-bound
JavaScript to replace REST events with AJAX ones based on the URLs already in the HTML.
Google doesn’t run JavaScript, so it still needs to get around!
Detecting if an incoming HTTP request is coming from AJAX instead of REST is easy too, you don’t have to send any
special tokens or headers from your JavaScript code.
if (@$_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
//code to deal with AJAX response
};
Having the site work without JavaScript increases user trust, increases the platforms you support without any extra
work, increases SEO
, reduces maintenance and best of all,
allows people to click through your site at super speed when they know where they want to go.
Provide Proper Fallbacks for Flash Content
Assuming everybody has Flash doesn’t cut the mustard any more, there are more diverse platforms in use—that
don’t support Flash—than there were years ago; iPhone for one. People are blocking Flash with AdBlock, NoScript
and FlashBlock.
If people can’t see your content then you lose out. There are almost always better ways of presenting content to
users without using Flash, and if you have to use Flash then don’t provide a lame cop-out excuse like “Install
Flash” as the only fallback message. Describe what the actual content is, why you can’t view it and provide it
in an alternative format (such as an image).
This especially applies to videos. I don’t have Flash installed, telling me to install Flash is just annoying,
when there’s plenty of other ways you can give me the content. Why don’t you provide a download link for the
video file, huh? Even better than that, modern browsers support HTML5 <video>
that requires no
plugin at all—use that instead!
If you are embedding video you should be using Video for Everybody—a
comprehensive solution that uses native HTML5 <video>
in browsers that support it, then falls
back to Flash for other browsers.
There is no reason anybody should be staring at a broken plugin icon anymore.
Clean Up the Head
You can really fill the head element with junk if you want to.
- Don’t use a favicon link:
-
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
/favicon.ico
is assumed by default, putting this in the head is just
extraneous bytes. If you need to store your favicon somewhere else (why? No why? No really, why?)
then just mod_rewrite it to /favicon.ico
to avoid 404s and wasted
HTTP-requests from browsers / aggregators assuming the default.
- Don’t use keywords / description:
-
All SEO
is bunk. Paying for SEO ‘specialists’ to wave their magic wand over your site
is no more material than a pair of emperor’s clothes. If you have clean, tidy, semantic markup,
have avoided text in images and have a sensible and clear system of navigation that doesn’t
depend on Javascript, then Google will have no problem understanding your site.
To that end, I have found that filling the head full of keywords is a
waste
of time. Camen Design appears on Google without
any issue. Seriously, drop the
voodoo and witch doctors, it’s not the ’90s anymore.
Styleheets First
To give a feel of snappiness, you want to get the structure rendered as soon as possible, ideally before any images
have even loaded. It’s critical therefore to get the stylesheet to the user as soon as possible. Any HTTP-requests
before the CSS sheet are wasting valuable time!
Therefore, don’t place any <link>
or script elements above the
stylesheet in the HTML head. If you really want to save a few milliseconds more for dial-up users, put the
stylesheet above the <title>
!
Add Height & Width on <img>
Tags
One thing that really annoys me is when you view a site with a lot of images and as you’re reading, the
page is jumping all over the place as the images load. If you define the correct height and width attributes on
image tags, then the page will render faster (less reflows) as well as allowing your users to get on with reading
without disturbance whilst the images load.
If your HTML is outputted by a CMS and the height and width attributes
are not added, then either modify the code to look up the image size
(getimagesize
in PHP), or hound
the developers until they do.
Optimise Images
All imaging software—and especially Adobe Photoshop—output inefficient JPEG and PNG files that waste
sometimes even hundreds of kilobytes in needless information. There are a number of tools out there that can
losslessly reduce the file size. I’ve seen as much as 1 MB or more
saved from a gallery of thumbnails.
ImageOptim
ImageOptim combines multiple PNG (and JPEG) optimisation tools into a
simple drag-and-drop interface. Everything it does is lossless, based on optimising the PNG compression parameters
and removing excess hidden data (such as EXIF in JPEGs).
43% bandwidth savings and all you had to do was drag-and-drop!
PNGNQ
pngnq is a command line tool that quantises 24/32-bit PNG files into
near-perfect 8-bit PNGs. The results are stunning. It
also maintains full alpha transparency, perfect for website graphics! (yes, it is quite surreal having a 256-colour
image, with full 256-level alpha, but it works!). Website graphics are not usually going to be using as many colours
as a photograph so pngnq is perfect for being extra brutal with saving bytes.
Reduce HTTP-Requests
Bandwidth is not the problem when it comes to speed, even on dial-up. The browser can only do a limited number of
simultaneous HTTP requests (usually between 2 and 6). That is the bottleneck that you are fighting against.
By whittling the number of HTTP-requests down to an absolute minimum, you will make the time between one page and
the next almost instantaneous.
Think of it this way: in a worst case scenario, a single HTTP-request could take up to a second alone if the server
is under heavy load or if the bandwidth is already saturated.
Combine Print Stylesheet With Main Stylesheet:
Even if a stylesheet in the head uses media="print"
the browser will still download it regardless.
When printing or in print-preview, nothing new can be downloaded, it has to already be in cache. Therefore having a
print stylesheet in the HTML head is wasting an HTTP-request!
If you include the CSS print declarations in an @media
block in the main stylesheet then the same
amount of data is being downloaded, but the number of HTTP-requests is reduced, allowing the browser to be busy
downloading something else. If your CSS sheet is gzipped then the size of the combined stylesheet will be less than
two separate sheets.
Combine Javascript Files:
Again, being brutal with HTTP-requests, merge JavaScript files into one when publishing.
I once wrote a
build-system that
‘compiled’ a web-app by searching through Javascript files and finding instances of a function called
$import
(which just loaded in the named Javascript file), and
replaced
the function call with the contents of that file. I used this same method to also combine @import
statements in CSS sheets with the imported sheet to combine multiple sheets into one.
Use the YUI Compressor to compress JavaScript files by
removing extraneous whitespace and comments &c. Google’s
Closure Compiler is a more powerful tool that rewrites the
JavaScript file to be as small as possible.
If you’re writing swathes of code that have to be spread across many files, it’s well worth investing time in
scripting a decent build system to ‘compile’ the site before uploading to a live environment, or using a
server-side language like PHP to do this and then cache the result.
Use CSS Sprite Sheets:
Use sprite sheets to combine various icons and imagery into
a single image file. This works wonders in most cases but has a few drawbacks. It’s harder to update your graphics
afterwards, and it has some issues with browser zooming if you haven’t left sufficient space around elements. Use
this method with the image optimisation methods earlier for solid speed gains.
Use Base-64 Encoded Images:
Most browsers support base-64 encoding (IE8+), and
IE6 and 7 can be tricked into
supporting it (but this would ideally require a script to automate).
Base-64 encoded images can be placed inline in the HTML or in the CSS:
<style>
/* notice that in CSS, “\” is used to break lines, though in reality you would probably not use line-breaks */
img {background: url("data:image/png;base64,\
iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKBAMAAAB/HNKOAAAALVBMVEUAAAD////+/v6ezPpbjrIyicIAadYAZukAZu\
4AZvUAZvsAZs0AZswAZcsAZcmXfdS2AAAAAXRSTlMAQObYZgAAAElJREFUeF4VxKENgDAQQNFvUK25BEXOMUHrimUB\
EgRbsAeSERpQN8uNwDDkzMPMgC7jFh6E7fzo+3wr71UXZUjPqpCnEoqE7v4Dv7MOC059M/cAAAAASUVORK5CYII=")
no-repeat center center;}
</style>
<!-- in HTML “\” is not used because of normal HTML white-space collapsing -->
<img src="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKBAMAAAB/HNKOAAAALVBMVEUAAAD////+/v6ezPpbjrIyicIAadYAZukAZu
4AZvUAZvsAZs0AZswAZcsAZcmXfdS2AAAAAXRSTlMAQObYZgAAAElJREFUeF4VxKENgDAQQNFvUK25BEXOMUHrimUB
EgRbsAeSERpQN8uNwDDkzMPMgC7jFh6E7fzo+3wr71UXZUjPqpCnEoqE7v4Dv7MOC059M/cAAAAASUVORK5CYII=" />
There are online converters to get the
base-64 string for an image, but I use
Image to Data, a nifty
droplet that copies the base-64 string of any file you drop on it to the clipboard.
Base-64 encoded images are larger than the original file (by a third), but if you have multiple base-64 images in a
stylesheet and then GZip the sheet, the overall gains of less HTTP-requests and GZip acting over multiple files
combined will far outweigh the size gain converting to base-64. On this site, it’s the difference between
80 KB of CSS+images, and 22.8 KB for one CSS file with the images inside.
Because of the increase in data size with base-64, it is vital that you optimise the images
you are converting as much as possible—every single byte counts. Combine ImageOptim, PNGNQ, base-64 encoding and
GZip and you will defy the very Gods with your insane levels of compression.
GZip What You Can
Save bandwidth for both you and the user by compressing text-based content such as HTML, CSS and JavaScript files.
Ideally you should compress the HTML/CSS & JS as part of your build / publishing or caching system (can be done
using PHP’s gzencode
function).
You can then tell Apache to inform browsers that the the content is compressed in your .htaccess file:
AddEncoding gzip .html .css .js
You can alternatively use
ob_gzhandler
to automatically
compress the output when your PHP code has finished running and is sending the results to the browser.
If you don’t want to have to compress your files every time you publish, or force your CSS/JS through PHP every
request, you can get the server to compress files during output. Bear in mind though that this will increase CPU
usage on the server and might not be ideal under heavy traffic; it’s always better to pre-compress your files.
SetOutputFilter DEFLATE
AddOutputFilterByType DEFLATE text/html text/css text/javascript text/plain
Imitate Background Images With Colours
An effect that adds to the perception of speed is to use the CSS to closely represent the page’s design without
images. If you view the page without images, is the page layout still communicated via the same colours?
For everything with a background image, set a matching background-colour to act as a ‘placeholder’ for the
image, and where possible, design your HTML structure such that background colours can be used to represent the
layout of the site when images are not present.
On Tripology, without images, everything just turns a light
shade of blue, and no structure is communicated.
Simply put—the website should look almost as good without images, as it should with them.
Write / Output Cleanly Indented HTML
The HTML on this site, in fact, every site I’ve written—CMS or not—has had clean HTML, nicely indented and
human-readable. Whilst not necessary for all kinds of site, this particular site is very much designed to encourage
reading of the source.
There are other benefits though of outputting clean HTML. It greatly helps with debugging HTML / CSS issues, but
really the benefits are not the result, it’s the fact that it takes a keen eye, patience and a lot of love to get
a big, heavy 10’000+ line CMS to output perfect HTML and that careful consideration whilst achieving that will
ensure that you’ve gone over your codebase with a fine-toothed comb and probably end up fixing and improving tons
more than just HTML.
Clean HTML makes for a clean codebase too.
Drop Internet Explorer 6 Support
A number of websites, including Apple’s Mobile Me have already taken
the lead in dropping support for Internet Explorer 6. The trend is
unavoidable.
Think of it this way:—given that there are more people using Firefox 3 (which passes Acid 2 and supports
<canvas>
) than IE6, the only users of IE6 who can’t upgrade to a newer version or a better
browser entirely are Win9X users and frozen corporate desktops. Anybody at home using IE6 is doing so out of a lack
of knowledge that they should install updates, or simply use a better browser.
You are working your arse off, wasting large amounts of time banging your head against IE6 bugs, for a group of
people who only need to be shown how to install a better browser. It’s like spending tons of money and effort in
healthcare dealing with the effects of a disease, when all the time you have the cure in your hand and just need to
give it to the people, or tell them where to get it.
The lack of +
and >
selectors mean that IE6 won’t go near an element without a class or ID in sight. This is insane to be writing code
this way. This website has no IDs, no classes and no DIVs to show that crazy tag-soup is not necessary.
You will be able to produce far greater things if you throw away the millstone around your neck that is IE6 and
start learning everything that’s been possible for the last five years.
Do Not Block Browsers for ‘Compatibility’
This is going to be quite controversial coming from me when I’ve just said to you above to drop IE6 support and
even my own site does not display correctly with Internet Explorer, but don’t bring up a splash
screen that outright blocks Internet Explorer (any version), or any browser for that matter from accessing
the content of your site—no matter how
pretty said screen looks.
If you don’t like IE6, don’t waste your time writing messages (or drawing pictures) for it (you haven’t got
Stockholm syndrome have you?). Would you outright block Lynx users, or Dillo users or any user of an alternative
browser that isn’t ‘compatible’ with your site? Why attack only IE6 when the list of browsers that will be
compatible with your site is smaller than the list that are not?
The fact your site looks wrong is besides the point, somebody’s life could depend on being able to access the
content on your site when all they’ve got is IE6 because of whatever reason. I’ve had to access stuff on my site
using IE when on other people’s computers or at a public library. You yourself should know that all that matters
is the raw text in those kinds of desperate situations, not how it looks.
Completely blocking any browser—IE6 included—goes against the very nature of HTML and CSS, formats that are
designed to be universally accessible and still be readable with even the littlest of support.
If you are really concerned about how your website looks on an eight year old browser (would you honestly still use
and support Netscape 6?), then place a message at the top of the page telling the user to upgrade their browser, but
don’t hide the content, the text still matters to the user.
If the layout and content is totally broken by IE6’s partial CSS support, then consider using
“Universal Internet
Explorer CSS”, a stylesheet that provides a back to basics design for IE6 that can communicate the
text clearly and forego your complex layout completely, allowing you to focus support on better browsers.
Any suggestions or comments, send them my way;
hit the e-mail link below.