This blog runs an out of the box Octopress setup. I love Octopress. It’s a great framework. It’s trivial to setup, gets out of your way and it just works.
Being passionate about web performance optimization, I decided to “eat my own dog food” and look at how I could improve the load time of my blog.
I’ve measured the homepage of the blog with my usual weapon of choice, WebPagetest. Using Firefox and Chrome roughly yielded the same results:
- DOM ready fires at about 1.2 seconds.
- The page is fully loaded between 2.8 and 3 seconds.
- There are 21 HTTP requests for a total of 244KB.
all.js to make it smaller and moved the file from the head to the bottom of the page.
Then I removed the 3 script tags from
1 2 3
And I added the following to
The load time did not change: still around 2.8 seconds. However something broke: the sidebar fails to load my recent tweets because that code depends on some that were moved to the bottom of the page (as explained above). I fixed the dependency and merged all the twitter JS code into all.js. The twitter JS code can be found in
1 2 3 4 5 6
Disclaimer: this last change might need to be applied to other plugins or sidebar modules. Twitter is the only one I used and after this last change, my recent tweets were back.
source/_includes/custom/after_footer.html I now have:
1 2 3 4 5 6 7
This last change brings the DOM ready event to now fires at 0.8 seconds.
Brandon Mathis (the creator of Octopress) mentioned on Twitter his plans to integrate a JS preprocessor (in the same way than Octopress uses compass for CSS preprocessing). I would hope this could include the optimizations mentioned above.
After this change:
- DOM ready fires at about 0.8 seconds (improved by 0.4 seconds).
- The page is fully loaded between 2.8 and 3 seconds (no changes).
- There are 17 HTTP requests for a total of 237KB (saved 4 requests and 7KB).
Octopress includes the PT Sans font as a default and is including it on the page using
@font-face. I noticed a flash of invisible content (see screenshot below). The issue is even more noticeable on mobile devices, which tends to be slower. This is something I noticed on other websites using
@font-face as well (Octopress blogs or not).
Paul Irish explains the problem in this 2009 blog post. The flash of invisible content is actually here to avoid a flash of unstyled content (at least for WebKit browsers). When using
@font-face, the browser needs to download the font file. If the file arrives late during the page load, then the browser first shows the content without the font applied and switches to using the font as soon as it arrives. This is called a flash of unstyled content (FOUC for short). To work around this issue, WebKit engineers make the content text invisible until the font is loaded. This is better than the unstyled flash, but it is still an issue. To minimize it, the key is to load the font as fast as possible. Removing the
@font-face all together is a solution (the fastest font is the one you don’t have to load) but for now I wanted to keep using a custom font, so I started digging.
The first thing I discovered was that I was actually loading 2 fonts (Ubuntu Condensed for the headers and PT Sans for everything else). That’s 25KB and 59KB. One was loaded from my domain the other from Google’s webfont CDN. I removed the Ubuntu font as PT Sans was looking just fine for the headers. Also, PT Sans leverages Google’s webfont CDN. The load time dropped to 2.2 seconds. The DOM ready event fires now at 0.6 seconds. Great! Can we make it even faster?
Looking at my waterfall revealed that the font was loaded late after the DOM ready event. The font download finished at around 1.6 seconds. I am assuming that means the content is invisible until then (more on that later).
Paul Irish’s blog post mentioned another technique: inline the font in the CSS file using data URI. This is a good idea because it removes 2 extra requests (Google’s webfont CDN loads one CSS file and then the font file). Also, a CSS file can be gzipped which can lead to additional savings.
I removed the font face include tags from the
source/_includes/custom/head.html and added the following to the
sass/custom/_styles.scss file (note: I did not include the actual base 64 content of the font).
1 2 3 4 5 6 7
DOM ready happens slightly later at 0.8 sec but at this point the font is downloaded. Previously the font was ready at 1.6 seconds. This should improve the flash of invisible content problem.
Are we done with
@font-face? No. I noticed an issue in Internet Explorer where the font seems to never load. It turned out to be a great hint for the next step. Data URI length is limited to 32KB in IE8 (according to caniuse.com). Could I find a smaller font? A quick search for PT Sans lead me to Font Squirrel which had the same font as Google webfont. However, it was smaller: 18K instead of 59K. I am not sure where that difference came from. The only difference I could see was visually: while very similar, the Google’s webfont seemed to be more condensed than the Font Squirrel equivalent. In the end, I think the font is fine so I went ahead and added it to the CSS file.
To verify the impact of these optimizations we can use the comparison feature of WebPagetest which includes a film strip view as well as a video comparison service. The film strip screenshot below shows that the optimized version at the bottom, as expected, loads about 1 second faster:
You can view WebPagetest video comparison by following this link.
After this change:
- DOM ready fires at about 0.7 seconds (improved by 0.1 seconds).
- The page is fully loaded in about 2 seconds (improved by 1 second).
- There are 15 HTTP requests for a total of 172KB (saved 2 more requests and 65KB).
Optimizing with Cloudflare
Another thing I wanted to investigate was CloudFlare. I am running this blog behind CloudFlare’s security and performance proxy and was wondering about how the various settings could affect the load time and if CloudFlare was helping my blog to load faster.
WebPagetest pointed out that I was not setting the far expire header properly for my assets. CloudFlare actually takes care of that. The default value is pretty low, it is set to 4 hours. I tweaked it to use the recommended 30 days which improved my caching score on WebPagetest.
Another benefit is the CDN: the assets of my blog are deployed on CloudFlare’s CDN. This is totally transparent to me (I did not have to make any changes to my blog’s code) and is great for performance. The CDN stores content closer to the user hence allowing faster delivery. I am running out of time here, but I guess the impact could be verified with Webpagetest. One can pick various test locations and compare the performance with and without CDN.
I started with 21 HTTP requests for a total of 244KB and a page loading in about 3 seconds. After optimizations, the page is down to 15 requests for a total of 172KB. The page now fully loads in about 2 seconds.
This experiment was very interesting. The big take away was learning more about
@font-face performance implications. I think barebone Octopress out of the box performance is not bad at all: the load time of my blog prior to the changes was decent. Yet, I was able to squeeze a little more speed with a few simple changes. I will contact Brandon Mathis (the creator of Octopress) to see if he would be interested by some of these tweaks. With Octopress being open source, patches are as easy as a pull request ;)
Now it’s your turn! Do you have an Octopress blog? How is your load time? If you try the above tips, do you see any improvements? Do you have any other tips that I might have missed? Contact me via the comment form below, Twitter or the Hacker News thread I’d love to hear from you :)
Update September 2012
After weighting the pros and cons about the usage of @font-face, I’ve decided to remove the custom font I was using. In the end, I value speed more than fancy typography. A basic font like Helvetica is perfectly fine for this blog :)