Background
The design and user experience of websites has been important to me for a long time. Every website I develop is fully responsive. Links are big enough to tap on mobile and text is legible on all devices. However, there’s been one area that I’ve been neglecting, and it’s equally as important as how the look and feel of a site; namely, performance. How fast does a website load? Turns out that the longer it takes to load, the more viewers you lose. If your load time gets up past 3 seconds, you’ve got problems. Also turns out, WordPress is notorious for being slow.
However, the good news is that we can take steps to address these issues. During my research, I never found a long, comprehensive list of everything that I need to do. Instead I found a lot of scattered and out of date information. So for my own future use and in case it might help any of you reading, I’m going to list and discuss everything that I’ve done (and still need to do) with my own website in the pursuit of performance.
I’ll also note, this guide is intended for the little guys. People who are running on cheap hosting and don’t have the cash for expensive dedicated servers of CDNs. Yes, paying for better hosting is going to boost your speed, but there are a lot of things you can do that don’t cost money, and those are where I’m going to focus. Also, this is for WordPress installations.
Sections
- Move JS to The End of Page
- Move CSS to The End of Page and Inline Above-the-Fold Styles in Head
- Optimize Images
- Minify CSS
- Minify JS
- Minify HTML
- Cache Resources (CSS, JS, Images, etc)
- Compress with GZip
- Reduce the number of HTTP Requests
Move JS to The End of Page
Problem
Javascript is render-blocking. That means that if you have a script that is linked (meaning it’s a separate .js
file), the browser will stop rendering your page until it finishes downloading the script.
Solution
Place your Javscript files at the end of the page, instead of in the <head>
.
Example
Change this:
<html>
<head>
<title>My Website</title>
<link rel="stylesheet" type="text/css" href="http://www.website.com/css/front.css" media="all" />
<script type="text/javascript" src="http://www.website.com/js/front.js"></script>
</head>
<body>
Content
</body>
<html>
To this:
<html>
<head>
<title>My Website</title>
<link rel="stylesheet" type="text/css" href="http://www.website.com/css/front.css" media="all" />
</head>
<body>
Content
<script type="text/javascript" src="http://www.website.com/js/front.js"></script>
</body>
<html>
The main thing to note here is that the <script>
element is right before the closing </body>
tag.
Move CSS to The End of Page and Inline Above-the-Fold Styles in Head
Problem
CSS is render-blocking, just like Javascript. Again, that means that if you have a stylesheet that is linked (meaning it’s a separate .css
file), the browser will stop rendering your page until it finishes downloading the stylesheet.
Solution
Place your Stylesheet files at the end of the page, instead of in the <head>
.
Example
Change this:
<html>
<head>
<title>My Website</title>
<link rel="stylesheet" type="text/css" href="http://www.website.com/css/front.css" media="all" />
</head>
<body>
Content
<script type="text/javascript" src="http://www.website.com/js/front.js"></script>
</body>
<html>
To this:
<html>
<head>
<title>My Website</title>
<link rel="stylesheet" type="text/css" href="http://www.website.com/css/front.css" media="all" />
</head>
<body>
Content
<link rel="stylesheet" type="text/css" href="http://www.website.com/css/front.css" media="all" />
<script type="text/javascript" src="http://www.website.com/js/front.js"></script>
</body>
<html>
The main thing to note here is that the <link>
element is right before the closing </body>
tag. Now, you may do this and say, woah, my page looks horrible for a moment and then flashes into place. That is because the page is being rendered with your stylesheet, which is then being applied after the page download finishes.
This flash of unstyled content can look quite bad, depending on how much styling you’ve done. Here’s what my website looks like after I move the stylesheet to the end of the page:
Terrible. Good news is, you can have the best of both worlds, possibly. The trick here is to split your CSS into two files. The first file contains only the styles that apply to “above the fold” content. The fold is a reference to physical news papers, which fold in half. In a website, content which is metaphorically “above the fold” is the part of your webpage that is visible immediately, with no scrolling. Everything below the bottom of the browser, that the user has to scroll to see, is below the fold.
If we take the styles that apply to everything that is above the fold, and then place them inline inside the <head>
element in a <style></style>
element, then we won’t see that flash. The rest of our styles we can then load via a regular external stylesheet which we place in the footer.
In essence, we are loading the styling for what we see immediately, immediately, and delaying loading the styles for what we don’t see immediately. It can be difficult to decide what to split, I’ll grant. This one is still on my own to-do list. Here’s some further reading for some methods on figuring out what styles are critical.
Detecting Critical CSS For Above-the-Fold Content With Paul Kinlan (Video)
Detecting critical above-the-fold CSS
Optimize Images
Problem
While SVG is superb for things like icons, the PNG and JPG images are going to remain widely used for the foreseeable future. Unfortunately, they are normally quite large in terms of file size. Anything we can do to cut down on the size helps out with page load times and overall data usage (a big concern for mobile devices).
Solution (Mitigation, at least)
We have two options here. The first is lossless optimization, which will typically reduce the file size by about 20% without changing the image’s appearance at all. The second is lossy optimization, which can reduce the file size by 60% to 80%, with very little change in the image’s appearance (most of the time you can’t tell unless you zoom in).
There are a lot of tools and methods to accomplish this optimization.
Manual: If you don’t have a huge number of images, there are a number of drag and drop optimizing websites that will let you upload your images and optimize them for you. The best two I’ve found are Kraken.io, and TinyPNG.com.
Grunt: Additionally, you can implement image optimization into your workflow in several ways. Grunt has a built-in free plugin to do this, and Kraken has a Grunt plugin as well. Kraken is far superior, but it costs money if you use the Grunt version.
WordPress: Additionally, there are WordPress plugins for Kraken and TinyPNG which will automatically optimize any images you upload. The Kraken plugin costs just like it does through Grunt, but the TinyPNG allows you to create an account and optimize 500 images per month for free. (This is the method I use).
Minify CSS
Problem
A typical stylesheet has a lot of white space. A good stylesheet has lot of comments. Comments and proper white space make the sheet easy to understand and easy to maintain, but they cause the file to be bigger than it needs to be, plus they add to the time it takes the browser to render.
Solution
Minify the stylesheet by removing the comments and whitespace. Typically this is done in a second file called x.min.css (for the original working copy being x.css). This can be done manually, via an online tool, but I prefer a Grunt task. I have the CSS for my website broken into 7 separate files, which I first combine and then minify, using Grunt. I use grunt-contrib-concat and grunt-contrib-cssmin. This makes things super easy.
Example
Change this:
a {
outline:0;
color:rgb(30, 120, 150);
font-weight:bold;
}
a:hover {
color:rgb(200,0,0);
}
a.block {
display:block;
text-decoration:none;
padding:10px 0;
margin-top:25px;
background-color:rgb(30,120,150);
color:white;
text-align:center;
}
To this:
a{outline:0;color:rgb(30, 120, 150);font-weight:bold;}a:hover{color:rgb(200,0,0);}a.block{display:block;text-decoration:none;padding:10px 0;margin-top:25px;background-color:rgb(30,120,150);color:white;text-align:center;}
Minify JS
Problem
The problem here is exactly the same as above in the Minify CSS section. A typical script has a lot of white space. A good script has lot of comments. Comments and proper white space make the script easy to understand and easy to maintain, but they cause the file to be bigger than it needs to be, plus they add to the time it takes the browser to render.
Solution
Minify the script by removing the comments and whitespace. Typically this is done in a second file called x.min.js (for the original working copy being x.js). This can be done manually, via an online tool, but I prefer a Grunt task. I use grunt-contrib-uglify. This makes things super easy.
Example
Change this:
$(document).ready(function(event) {
$('#menu').click(function(event){
event.preventDefault()
$(this).toggleClass('open')
});
});
To this:
$(document).ready(function(){$("#menu").click(function(e){e.preventDefault(),$(this).toggleClass("open")})});
Minify HTML
Problem
Just like scripts and stylesheets, the actual HTML that the browser receives it typically fully of extra whitespace. While this makes it easier to read, it adds rendering time and increases render time. That said, this seems to be a lesser concern than with scripts and stylesheets, so if you are going to ignore anything, ignore this.
Solution
Minify the HTML. This gets tricky when you are using WordPress. I haven’t really researched a lot of ways to do this, because it gets taken care of for me by a WordPress plugin which I installed for caching. I use W3 Total Cache, which I’ll talk more about in the next section. It does more than just cache files. One nice feature is that it minifies your HTML.
Update I am a bit confused here actually, because when I look at my pages right now, they aren’t minified. Yet Google PageSpeed says they are. So I need to do a bit more research, and I’ll update this section when I do.
Cache Resources (CSS, JS, Images, etc)
Problem
Downloading all the resources for your website (stylesheets, scripts, images, etc) takes a long time.
Solution
If we can have a user’s web browser cache these resources (save to the local machine), then our website will load faster every time a user visits again. This is especially useful for resources which don’t change. The length of time that a browser will cache a file is determined by that file’s “expires” header. We can give all of our files a “far-future” expires header, by adding some code to the .htaccess
file in the root of our web directory. You can access it via FTP.
Example
# Configure Etags for caching optimization
FileETag MTime Size
# Add correct content-type for fonts
AddType font/ttf .ttf
AddType application/x-woff .woff
# enable caching - disabled for dev
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 seconds"
ExpiresByType image/vnd.microsoft.icon "access plus 9 years"
ExpiresByType image/x-icon "access plus 9 years"
ExpiresByType image/jpeg "access plus 9 years"
ExpiresByType image/png "access plus 9 years"
ExpiresByType image/gif "access plus 9 years"
ExpiresByType image/svg+xml "access plus 9 years"
ExpiresByType font/ttf "access plus 9 years"
ExpiresByType font/otf "access plus 9 years"
ExpiresByType application/vnd.ms-fontobject "access plus 9 years"
ExpiresByType application/x-woff "access plus 9 years"
ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
ExpiresByType text/css "access plus 604800 seconds"
ExpiresByType text/xml "access plus 604800 seconds"
ExpiresByType text/javascript "access plus 604800 seconds"
ExpiresByType application/javascript "access plus 604800 seconds"
ExpiresByType application/x-javascript "access plus 604800 seconds"
</IfModule>
Compress with GZip
Problem
There isn’t really a problem here other than the problem that all files are big.
Solution
Compress ALL the things, using Gzip. It’s kinda complex, but you don’t need to understand it to use it. As I mentioned earlier, I use W3 Total Cache, and one thing that it does it take care of Gzipping everything.
Reduce the number of HTTP Requests
Problem
One final problem is that every HTTP request is going to slow down your site. A site that seven small CSS files is going to load more slowly than a site with one large one. However, it’s nice to be able to develop with out stylesheets broken into managable chunks.
Solution
- Develop with smaller files, and then combine everything before you minify. I use Grunt to do this for my CSS files, and I only have one JS file anyway.
- Take small files and inline them (meaning add them to your actual HTML document).
Final Thoughts
This is a very lengthy read, but with it you can make your site load super fast. I’ve implemented all of these steps except for inlining critical above-the-fold CSS, and my Google PageSpeed score has risen from 65 to 91. My media page loading time has gone from 3.5s to 1.2s. I still have issues one a few pages with external dependencies. I’m using Jetpack stats, which is slowing things down (need to change over to Google Analytics), and I have an embedded Google Map on one page, which causes a lengthy slow down (though I’ve switched it mostly to lazy load). Overall though I can really tell a difference in how fast pages load, especially on mobile. This stuff works.
I am still a novice though, when it comes to performance, so if I’ve made any mistakes or you know of anything better, let me know in the comments and I’ll update it. I’m planning on regularly editing this anyway in the future to keep it up to date.
Leave a Reply