Building High Performance Websites
When it comes to the web, speed is everything. Saving milliseconds of load time can have a profound impact on your business. Faster websites lead to higher visitor engagement, retention, and conversions. For this reason (among many others), optimizing web performance should be one of your top priorities. It’s so important that Google factors it into your search engine ranking.
As a platform for front-end websites and apps, Divshot is specifically designed to deliver the best performance possible with minimal effort via CDN. Building static websites with just HTML, CSS, and JavaScript already gives you a leg up since there’s no server-side processing involved. Using a CDN supercharges and delivers your website across the world. Out of the box, Divshot gives you:
- CDN with SSL for High-Performance Apps
- GZIP Compression for Text-Based Content
- Automatic
Cache-Control
Headers with Configuration - SPDY 3.1 Support for Modern Browsers
However, even if you build a static website and use a CDN hosting provider with all the trimmings there’s still room for improvement.
Recently I optimized our lander to solve my biggest pet peeve in web performance: White flashing between page loads. You know, when you click a link and the screen turns completely white before loading and rendering the page.
We want our website to load instantly. When visiting different pages, the design should remain intact like so:
In this article I’ll cover some tips, resources, and tools you can use to achieve this exact same goal.
Web Performance 101
If you’re new to tackling web performance in your websites or apps, these resources are useful:
Google - Web Fundamentals: Optimizing Performance
Covers optimization for both web apps and content-based sites, including render trees, layout, and paint. More than just guidelines, it explains how the browser actually loads and renders a page.
Mozilla - Tips for Authoring Fast-Loading HTML Pages
Provides a list of general tips for speeding up your HTML pages. Some of these were applied in my lander analysis below.
Yahoo - Best Practices for Speeding Up Your Web Site
An in-depth guide of best practices for web performance. Easily filter by category.
Chrome Developer Tools
Developer Tools in Chrome provides a wealth of insight in the performance of a given page. In particular, you’ll want to look at the Network
and Audits
tabs.
The Network
tab allows you to monitor incoming requests and load time.
The Audits
tab allows you to analyze network utilization and web page performance. After auditing a page, you’ll get a list of actionable suggestions:
PageSpeed Insights
PageSpeed Insights from Google helps you identify performance best practices applicable to your site. It’s available online and as a Chrome extension directly integrated in Developer Tools.
Lander Analysis
After reading up on web performance guides and analyzing our lander with PageSpeed and Audits, I decided to implement several suggestions one at a time on our lander.
We were already doing plenty of things right. jekyll-assets automatically minified and concatenated source files. Our HTML was well organized and synchronous scripts were loaded at the bottom of the page. Everything was served via CDN with GZIP compression. Our lander was fast, but not instant. Here’s what I did to get us to the next level.
Leaner Dependencies
It goes without saying that frameworks and libraries can bloat your website quickly. For instance, there’s a lot of components in Bootstrap you probably don’t need. If you run Audits on a website with Bootstrap you’ll probably notice a lot of unused CSS selectors:
As a result, this leads to larger file sizes and higher latency.
For the Divshot lander we needed to customize the grid system and tweak a couple variables, so we implemented bootstrap-sass. To bring down the file size I decided to only include the components we were using and imported them explicitly:
@import "bootstrap/variables"
@import "bootstrap/mixins"
@import "bootstrap/normalize"
@import "bootstrap/print"
@import "bootstrap/scaffolding"
@import "bootstrap/type"
@import "bootstrap/code"
@import "bootstrap/grid"
@import "bootstrap/forms"
@import "bootstrap/buttons"
@import "bootstrap/component-animations"
@import "bootstrap/dropdowns"
@import "bootstrap/navs"
@import "bootstrap/navbar"
@import "bootstrap/modals"
@import "bootstrap/tooltip"
@import "bootstrap/utilities"
@import "bootstrap/responsive-utilities"
If you're not using bootstrap-sass
you can still customize your own version of Bootstrap on the official website and download the compiled build.
I also decided to trim down Lo-Dash by using a custom build with only the functions we needed.
This dramatically improved the file size of our concatenated stylesheets and scripts. Once you’ve finished developing a website, it’s a good idea to take a closer look at the frameworks and libraries you’re using to see if you can reduce the bloat.
External CDNs
If you’re not customizing a popular framework or library and you need to take advantage of everything it has to offer, you should consider utilizing a CDN that will freely host it for you.
The advantages of doing so are numerous. For one, it’s on a CDN. Secondly, it frees up more of your local content to be downloaded in parallel since it’s on a separate domain. Lastly, it may load instantly if it was already loaded on another site and cached in the user’s browser.
In our case, I figured jQuery would be the perfect candidate for an external CDN. Dropping jQuery from our codebase resulted in a much smaller file size. All I had to do was add the script to the bottom of the page:
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Google hosts many libraries for free. Bootstrap CDN from MaxCDN is great for Bootstrap and Font Awesome. cdnjs and jsDeliver provide more options for less popular libraries.
Page-Specific Dependencies
When you’re building a content-based website, you’ll typically have a global script that imports libraries and plugins for use across the entire site. However, some dependencies may only be used once.
Our features page had some fairly large dependencies like Snap.svg that were only being used specifically for that page. Since I was originally planning to use it on multiple pages, it was imported in the global script.
It’s always a good idea to circle back and determine whether or not something needs to be requested when your codebase gets heavier. I decided to load a separate script with libraries specific to the features page only when it was requested, rather than upfront on the homepage.
Related: The JavaScript Packaging Problem
Web Fonts & Icon Sets
Use sparingly and only what’s needed. Having a variety of web fonts along with multiple font weights for each can add up significantly. On Divshot we make heavy use of custom web fonts. I was able to remove a couple font weights we weren’t using in Typekit and reduced the request size by around 80-100 KB. Google Fonts even shows you a gauge to see the impact on page load time:
It’s also important to look at your icon set and determine if you can trim it down. Services like IcoMoon allow you to use only the icons you need. Use an external CDN for icon sets such as Font Awesome to reduce latency.
The Little Things Add Up
When it comes to web performance, even the smallest tweaks can add up in a big way. The following weren’t necessarily game changers but helped:
- Use expensive CSS properties sparingly, such as
box-shadow
- Remove unnecessary backgrounds and design-related assets
- Clean up and organize stylesheets/scripts
- Set width and height on images
Even if you’re still getting a delay between page loads, you can always set the background of the page to match your design for a smoother transition and eliminate the white flash. Since we have a dark lander, I decided to set the background to black before the concatenated stylesheet is loaded:
<style type="text/css">html{background: #000}</style>
{% stylesheet lander %}
Several things I’d like to do in the near future:
- Use CSS spriting for images (automate with Compass)
- Optimize images using image_optim in the asset pipeline
- Implement a separate cookieless domain for assets (recommended by Audits)
- Lazy load expensive plugins like jQuery Terminal upon interaction
Results
After deploying the new lander to production, we compared our previous version with the new version on WebPageTest.org. The results were fantastic:
- Reduced requests by 50%
- Dropped payload by 40%
- Rendered in half the time
View the test results for Divshot.com along with a video comparison.
There's hundreds of performance improvements you can make to achieve instant page loads. Some make a larger difference than others depending on your circumstances. In my case, trimming "one size fits all" frameworks like Bootstrap and using external CDNs along with Divshot's built-in hosting features made the most impact. Your mileage may vary, so review the resources and tools I provided. Let me know if there's any tips you'd recommend in the comments below!