9 ways to improve your page speed
Following my previous post, I show 9 ways on how to improve the speed of your web pages.
In my previous post, I talked about what your PageSpeed Insight score means. You may be asking, however, how can I speed my site up? Here are some tips I use to speed up my site, especially the Speed Index and First Meaningful Paint.
1. Add only your Critical CSS to your <head>
section
Rather than loading all your CSS in the <head> section. Only load the CSS needed to load the above the fold content. This makes sure the content loads quicker, as it doesn't have to download larger stylesheets. The content will then be styled by the Critical CSS until your full stylesheet is loaded later on at the end of the body.
Don't worry, you don't need to go through your Stylesheets trying to work out which should be critical. There's a couple of easy ways, if you're using gulp, you can use the gulp-critical-css. You can then add some code to your gulpfile to automatically create your Critical CSS for you. (check out my post on some awesome gulp plugins by the way)
There are also websites that can generate your Critical CSS for you, such as the Critical Path CSS Generator by Jonas Ohlsson Aden. (The basis of this is penthouse, a Node package that generates your Critical CSS)
Before applying Critical CSS
<head>
<link rel=stylesheet href=myawesome.css/>
</head>
<body>x§
<!-- your content -->
</body>
After applying Critical CSS
<head>
<style>
/* The styles needed for above the fold content */
</style>
</head>
<body>
<!-- your content -->
<link rel=stylesheet href=myawesome.css/>
</body>
2. Preload your CSS
The next tip is to load the CSS asynchronously. Using a JS library such as loadCSS you can load your CSS after the page loads. This stops a page from being slowed down by the download of stylesheets. Using loadCSS isn't a totally necessary step, but it helps with browser compatibility.
I generally keep the loadCSS library inline in the body. Followed by the stylesheet tags, with a little modification. First, you need to change your rel to preload and add some onload scripts. Next, you need to add a normal stylesheet embed inside a <noscript> tag so that users without JS still have a stylesheet.
So, extending from the above example, what would our page look like now?
<head>
<style>
/* The styles needed for above the fold content */
</style>
</head>
<body>
<!-- your content -->
<link rel=preload href=myawesome.css as="style" onload="this.onload=null;this.rel='stylesheet'"/>
<script>
/* loadCSS and loadCSS polyfill for rel=preload */
</script>
<noscript>
<link rel=stylesheet href=myawesome.css/>
</noscript>
</body>
3. Move your JS to the end of the body
If your JS is in your <head> section, a browser will stop loading your webpage until the JS has downloaded and executed. Then it will continue to load the webpage. This will slow down your First Contentful Paint. Putting your script tags before the closing </body> tag will help this. As it won't download and executes the JS until it's finished rendering the body.
4. Defer or Async your JS
Following moving it to the end of the body, add async or defer attributes to JS you don't need to load in any particular order.
Async
Adding the async attribute to your script tags will allow the browser to carry on rendering the document while downloading and executing the JS file. The downside to this is that it will execute as soon as it downloads. So if the file has or is a dependency, it may execute before the dependency has loaded. Yet if you have some standalone JS which isn't or doesn't have any dependencies, the async attribute will be perfect.
Defer
Adding the defer attribute to your script tag is very similar to the async attribute. Rather than downloading and executing whilst the browser carries on rendering the document, it will wait until the document has finished, then download and execute the JS.
5. Load your web fonts with WebFontLoader
If you're using web fonts on your website or app, you may notice when you load the page, the text disappears until the font has downloaded. Using WebFontLoader we'll be able to easily embed any external fonts into our page. It works well with Google Fonts or Typekit, but you can use your own fonts too.
So, let me give you an example of the JavaScript set up just before the closing </body> tag:
<script>
WebFontConfig = {
google: {
families: ['Roboto', 'Roboto:black'],
},
custom: {
families: ['Foco', 'Font Awesome 5 Pro'],
urls: ['//pro.fontawesome.com/releases/v5.6.3/css/all.css']
},
fontinactive: function(family, fvd) {
if (family === 'Font Awesome 5 Pro') {
WebFont.load({
custom: {
families: ['Font Awesome 5 Pro'],
urls: ['/assets/fonts/fontawesome-pro/css/all.min.css']
}
})
}
},
timeout: 2000,
active: function() {
sessionStorage.fonts = true;
}
};
(function(d) {
var wf = d.createElement('script'),
s = d.scripts[0];
wf.src = '//cdnjs.cloudflare.com/ajax/libs/webfont/1.6.27/webfontloader.js';
wf.async = true;
s.parentNode.insertBefore(wf, s);
})(document);
</script>
What does this actually do? Well, to start, we don't need to have any CSS to pull in Google Fonts, all you need to do is include the Fonts in the 'google' object. In this example were pulling in Roboto and Roboto:black. It's also similar to Typekit fonts. If you're using custom fonts, you can pull them in one of two ways: the normal way through @font-face, or in the 'custom' object. As you can see in the example above, we are using a font called Foco. This is being specified in the CSS in a @font-face. Whereas Font Awesome 5 Pro CSS is being pulled in via a URL.
Next, we have an if statement to fall over if the CDN fails. Then we set a time limit for a font to load before falling back, which is currently set to 2 seconds. We then set a sessionStorage variable to say they have downloaded the fonts.
Finally, we load in the JS library asynchronously.
Next, in the CSS you need to specify which fonts you want to use before and after the fonts have loaded. You can do this as follows:
body {
font-family: 'Helvetica', Arial, sans-serif;
.wf-active & {
font-family: 'Roboto', sans-serif;
}
}
This loads the font Helvetica, Arial or any other non-fancy font. Once the web fonts have finished loading, WebFontLoader will add the class wf-active to the body. At this point, the font will be replaced with the Webfont.
Then in the <head> section, we have the following JS:
<script>
(function() {
if (sessionStorage.fonts) {
document.documentElement.className += ' wf-active';
}
})();
</script>
This simply adds the class wf-active to the body, as font fonts should already be cached. So your fonts should show when a page loads straight away.
So what does all the above actually do?
When a user loads the page, they will see any text with the system fonts specified. Once the document is loaded and the JavaScript is executed. (Which should be before the closing </body> tag) The user should then see the fonts replaced with web fonts.
6. Pre-connect or Pre-fetch the DNS for external resource locations
Next, we can save some time asking for resources and waiting for a DNS lookup, and with preconnect, start the TSL and TCP negotiation. Then, once you request the resource from the remote location, it only has to download the file.
preconnect doesn't have the browser support of dns-prefetch. When the browser goes to download the file, it will take longer than preconnect due to the TLS and TCP negotiation.
I usually use preconnect, most main browsers support this feature. I'm looking at you IE (ergh).
It's really simple to add this to your page, simply add the following to your <head> section:
<!-- preconnect tag -->
<link href="//pro.fontawesome.com" rel="preconnect" crossorigin>
<!-- dns-prefetch tag -->
<link href="//pro.fontawesome.com" rel="dns-prefetch" crossorigin>
7. Enable compression on your web server
This ones a quickie, make sure you have compression enabled on your server. If you are in control of your own servers, all you need to do is edit your webserv config.
You can check whether your server already has gzip enabled by running a test over on GT Metrix.
KeyCDN have a great guide on how to enable this on your server.
8. Optimise your images (Huge improvement of page speed)
Optimising images is really important to a website's performance. I could write a blog post just on this. But I'll just give a few tips.
Make sure the image matches the largest resolution it needs to be.
Downgrade the quality and increase blur to decrease filesize.
Pick the correct format, make sure you're not saving large resolution images in a lossless format.
There are lots of other things you can do too. Use some next-gen formats, dynamically change image sizes etc.
9. Keep your advertising and tracking to a minimum
I know this is easier said than done, however a users experience can be ruined by a slow page speed. This experience can be made worse when it's not the content they're looking for or something they can't see at all.
It's something to keep in mind more than anything. A users experience is the most important aspect to keep a user engaged and to make them return again.