Please Support - Ride for the child

I’ve finally managed to take a look at the PageSpeed score of my Webknit website. I was scoring around 60/70 and I wanted to find out what I could do to improve it, and ultimately if I could achieve a 100% score on both mobile and desktop.

Before we go any further just take a look at the following image and see that is it possible to achieve a 100% score on both mobile and desktop.

pagespeed

HOWEVER it’s worth noting that while I was delighted with the score it’s not the holy grail that it’s made out to be. I had to sacrifice some key aspects of the website in order to achieve a maximum score. I also had to employ some dodgy code and development practices, some of which I would never normally consider doing.

Firstly I’m going to start with some of the techniques I used in order to improve the performance of my page. Some of these contribute directly towards the PageSpeed score, whereas others are just good practice. The end of the post will explain how I achieved the 100% PageSpeed score.

It’s worth mentioning that it’s important to consider the requirements of your site before making decisions, the BBC scores very low, but that’s not to say it’s a poor website. Some of these practices might not be achievable for whatever reason, it’s a developers job to find the right balance.

Minification

Pretty simple and straightforward. By simply compressing your CSS and JS, you can remove removing all unnecessary characters from your code without changing its functionality. Things like white-space, new lines and comments are all fantastic for readability, but they’re not needed for the code to execute.

I currently write SASS and use a grunt setup for my FE workflow, this means that my CSS/JS is automatically minified as I write code. It’s also important to mention that I only have one CSS and JS file at the end. All my CSS is compiled into one CSS file from the individual SASS files. My JS is the same, so all my code (plugins, snippets, etc) are complied into one document through my grunt setup.

Minified code means files are smaller and therefore quicker to parse and execute. Limiting the amount of JS/CSS you load means you’re restricting the number of HTTP requests that are required, resulting in faster websites.

Images

Images are generally the heaviest elements on a website, they can really slow a site down. I used ImageOtim, a lossless compressing tool, to reduce the size of my images. I also have an image compressor in my grunt build process.

ImageOptim is a free app that makes images take up less disk space and load faster, without sacrificing quality. It optimizes compression parameters, removes junk metadata and unnecessary color profiles.

Where possible you should always use SVG over a raster image, these can be embedded straight into the code (no http requests), and they’re also much lighter. It goes without saying that you should always use CSS over an image where possible, you can do some amazing stuff with CSS these days.

I was also impressed that PageSpeed was able to determine the size of html containers and the images that were being supplied to them. I had accidentally supplied a 500px image to a container that was only ever 200px at its largest, a quick resize and compression resolved that.

.htaccess file

Although I’m not too experienced with the .htaccess file I figured out some basics to help improve my PageSpeed score, the links to the original sources are below.

# BEGIN GZIP

AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript

# END GZIP

## EXPIRES CACHING ##

ExpiresActive On
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType application/pdf "access 1 month"
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType image/x-icon "access 1 year"
ExpiresDefault "access 1 month"

## EXPIRES CACHING ##

# use utf-8 encoding for anything served text/plain or text/html
AddDefaultCharset utf-8
# This applies to all the content serverd by the web server.

Active Gzip Compression – https://css-tricks.com/snippets/htaccess/active-gzip-compression/

Leverage browser caching – http://gtmetrix.com/leverage-browser-caching.html
Typekit and Google Analytics caused me problems here, I will explain more about that towards the end of the post.

Force charset utf-8 – http://httpd.apache.org/docs/2.0/mod/core.html#adddefaultcharset

Eliminate render-blocking JavaScript and CSS in above-the-fold content

Websites have to wait for all the CSS/JS to load before it can move onto the rest of the code. If you could provide inline styles for the above the fold/fundamental parts of the website, and then defer or asynchronously load blocking resources after, that’s an ideal solution for PageSpeed.

You should read this excellent article if you want to know more about async and defer.

Link elements

The most interesting issue was the fact some of my <a> links were not an acceptable size for mobile users. Google states that they require links to be at least 42px in height. I simply increased the padding on my footer link items, something I thought was a good recommendation.

How I achieved 100%

First of all I inlined all my JS and CSS, this meant I never had any HTTP requests or render-blocking code.
It goes without saying that this was difficult to maintain, and because my workflow doesn’t support this I was manually copying and pasting my code inline.  The CSS wasn’t too bad as it’s a relatively small site. However the JS was considerably larger, especially as I needed jQuery, Google Anatylics, a retina plugin I made and my custom code – safe to say things got messy. Perhaps it would be better to implement something like this server side on deployment?

Setting an expiry date or a maximum age in the HTTP headers for static resources instructs the browser to load previously downloaded resources from local disk rather than over the network.

^^ This was the most troublesome problem. I couldn’t solve Typekit so ended up removing it and using my fallback font to achieve the 100%. This is because it’s against their terms of service to host the js locally, and they set a short expiration header of 10 minutes so that if you make an update to your fonts it’s reflected relatively quickly. I tried to rip this code out and run it locally but there’s something in place to prevent it.

For Google Analytics I accessed the URL in the Chrome developer tools and pasted it inline, ensuring that my credentials were also inline below it.

ga('create', 'UA-26260989-6', 'webknit.co.uk');
ga('send', 'page view');

The worst practice I employed was to minify ALL my HTML. Again this is something that I did manually but it could be implemented on a server side build script. Safe to say that this is a maintainability nightmare, whatever you do don’t lose your original code!
I also had issues with my JS after minifying the HTML, e.g. shorthand JS was no longer working when minified.

And that’s it!!!

In the end it’s wasn’t a viable option for me to drop Typekit and minify all this HTML so I reinstated both of those percentage drainers. I was left with a 98% score on mobile and a 99% on desktop. Upon load the site weighs in at around 400kb (a figure that increased as my images kick in when they enter the viewport), 6 http requests (3 of which are Typekit) and loads in under a second.

I’m lucky as my site is a simple one with no CMS. I don’t depend on any 3rd party plugins and there’s not really much code to sort. If you’re looking to get a WordPress website to this kind of score then I wish you good luck!

I’m hoping I’ve not missed anything, if I have I will be sure to add it. If you’ve any questions, suggestions or recommendations then feel free to tweet me. I should also thank Jordan for his assistance with this exercise, he helped a lot.

Thanks for reading.