Performance Optimization for Websites Built With Craft

Performance optimization is an increasingly important consideration for every web project. Fast load times are essential not only for SEO, but also for your website visitors. According to Kissmetrics, 40% of users abandon a website that takes more than 3 seconds to load. What they see— or don’t see— in the first few seconds is going to leave an impression of the quality of your site.

Performance Testing Tools

We’ve found it very helpful to test a web page in several different testing tools and to save the results before and after each step of optimization. This shows us the performance gains we make after each step, and tracks our overall progress.

How We Optimized Our Own Site

Results on Google PageSpeed Insights before and after optimization

The screenshot above shows the process of how we optimized our web site in Craft CMS, our content management system of choice. First, we tested our site on webpagetest.org. Then we selected a single page to test. We chose a page from the blog as opposed to the home page, as the home page is static, while the blog entries are dynamic.

Result of test from webpagetest.org before optimization

Previously, we had taken a number of steps to improve performance, including:

So already we were seeing pretty good results, but we still had some work to do.

“80-90% of the end-user response time is spent on the front-end.” —Steve Souders

While most performance optimization is related to front-end, we wanted to see what performance gains we could squeeze out of the back-end as well.

The frontend/backend split of our tested page

Optimizing Our HTML

We began by optimizing Craft requests to the database. We use Matrix fields for content on most pages, and adding Craft Cache tags reduced the load time by 90ms. While that was a nice gain, we were really looking for some way to generate static HTML files. We came across a great Craft plugin to do just that in HTML cache, which we have customized to suit our needs. By removing the cache tags and utilizing this plugin instead, we were able to reduce load time by an additional 100ms. Now every page on our site is served up as a static HTML file, and there are no longer any requests to the database (after the page is generated/loaded for the first time). Furthermore, we minimized our HTML in order to save every last byte we could.

PD Cache Craft plugin

Another step we took was to move the source for SVG sprites from HTML into an external file that we saved to local storage. By doing this, we reduced the size of the document from 12.3 KB to 7.9 KB and load time from 184ms to 172ms. Finally, we added expire headers on HTML pages with the duration of one hour, so if a user returns to the same page within that timeframe, the load time will be just 1ms from the browser’s cache.

Adding an Expires Headers

We added a far-future expires headers in .htaccess file and we unset ETag headers for that resources as you can see on HTML5 Boilerplate htaccess file. We cached CSS and JavaScript files for one year, images and other media files for one month. When we update these files, we add a hashtag to the filename of new version like so: “main.12345.css”.

Using Web Font Loader

We load fonts from Google and Typekit asynchronously via Web Font Loader library to avoid page blocking while loading the fonts. The primary downside to loading fonts this way is Flash of Unstyled Text (FOUT). When this occurs, the rest of a page may render before the fonts are loaded. Google and Typekit fonts have some performance issues which may affect our optimization score.

Adding Lazy Load for Images

Lazy load scripts delay the loading of images until they become visible in the viewport. Using this technique, we reduce the initial server load so that a page renders more quickly. We’ve been using the Unveil.js plugin on our page and have found that it works well.

Coding for Speed

Here are a few pointers for writing faster CSS and JavaScript:

Pay attention to performance consideration as you write the code. Don’t wait until later and optimize.

Avoid unnecessary nesting of selectors in CSS, and use short names for CSS classes.