High Performance Mobile Sites

This lab will cover how to analyze the performance of your Moovweb experience and different techniques for optimizing that performance.

Outline

Course Materials

Check out our Guide to Mobile Performance and this Primer on Web Performance


The Importance of Performance

Performance of your mobile site is fundamental to how your mobile user feels about the site. For the average user, the following timeframes can be used as a guideline:

Performance Image

Remember, the page only has to look complete. Instant visual feedback gives the illusion of high performance.

Studies have shown that as people spend more time on their devices, they have higher expectations for performance. Bounce rate on mobile phones is around 45% if a page takes 6s to load!

Bounce Rate

(via Josh Frazer)


Analyzing Performance

There are 3 main performance metrics we look at when evaluating a site’s performance:

  1. The number of HTTP requests
  2. The size of the HTTP requests
  3. The time it takes to fire the DOMContentLoaded event

As a rule of thumb, you want:

  1. The number of HTTP requests to be < 15.
  2. The zipped size of all assets to be < 200KB and the largest asset on the page should be < 50KB.
  3. The DOMContentLoaded event should fire on an average-case 3G network in < 3 seconds.

The first step to improving performance is to analyze your current Moovweb experience to find critical areas for improvement. You can do this using your browser’s Network Inspector.

Network Inspector

The Network Inspector is a critical tool for understanding where you have performance problems on your site and how you might be able to improve in those areas.

Before beginning, clear your cookies and your cache and disable the cache for your testing.

The first thing we want to measure is the page loading time — how many requests and how long they took to download. The “Network” tab tells us the times taken for each aspect of the page to be received by the browser.

In the example below, you can see the JavaScript takes 0.35 seconds to load. You can see that the DOM content is loaded in 0.87ms (indicated by the blue line). The page has fully rendered (onload) after 1.29s (indicated by the red line).

Network Inspector

You can also take a look at the “Timeline” tab which will tell you how long it takes to render the page.

Network Inspector

See how long it takes for the assets of your website to load to try and identify any bottlenecks.

Google PageSpeed

Google PageSpeed will help you identify performance best practices that can be applied to your site. Simply download the Chrome extension and run a site analysis from your Web Inspector or visit PageSpeed Insights and enter the URL of your website.

PageSpeed

The resulting analysis will tell you the high priority tasks necessary to make your site faster.

You can use Network Link Conditioner to throttle your own internet connection to simulate a 3G network for testing.

Network Link Conditioner

How do I install Network Link Conditioner?

It’s found in the /Applications/Utilities/Network Link Conditioner folder. Double-click on the file inside (Network Link Conditioner.prefPane) to add the utility to the System Preferences window. If you can’t find it there, open up Xcode and under Xcode > Open Developer Tool > More Developer Tools, download the Hardware IO Tools for Xcode and then double-click the Network Link Conditioner.prefPane file.

For more questions on how to install check out this link from Stack Overflow.

Optimizing Performance

The second step in improving performance is to optimize the performance bottlenecks you’ve discovered from analysis. This generally includes optimization of images, JavaScript, stylesheets, Tritium, and caching.

Optimize Images

Generally, this means reducing images in size and resolution since high quality images aren’t as necessary for the mobile viewport.

To optimize your images, use the Moovweb Performance Mixer. The performance mixer will allow you to change the format of your images, resize them for different devices, and even change the image quality/resolution.

$("//img") {
  perf.optimize_image("src") {
    # Change image formats: jpeg, png, and webp!
    perf.format("jpeg")
    
    # Resize the pixels
    perf.width("120")
    perf.height("120")
    
    # Change the image quality: 0 - 100
    # This affects the image resolution
    perf.quality("70")
  }
}

You’ll also want to sprite your images. Spriting means taking a number of your images and converting them into one larger image. To learn more about spriting, go to our Mobile Styling Lab.

Finally, push the loading of large main images to after the load event.

Optimize JavaScript

Here is a list of techniques to improve performance by optimizing your JavaScript:

Optimize CSS

One of the easiest ways to test whether your CSS is slowing down the page is to resize the browser window and scroll up and down rapidly. The browser will take a long time to render if your CSS is bloated. In fact, the CSS stress test we mentioned above does just that — scrolling plus sequential disabling of CSS elements — to see which are the most costly. There are some elements that always tend to cause problems, such as CSS3 selectors. Animations should be used sparingly, for example.

By default, Moovweb minifies CSS when Sass is compiled (to “minify” is to compress all the CSS so rather than appearing on multiple lines, it only appears on one). We encourage the use of bundling stylesheets. All stylesheets should be imported into main.scss. This ensures that the page will only have to make one HTTP request for the stylesheets.

Optimize Tritium

The main way we can increase performance with Tritium is found in the XPath selectors we use. In particular, the “deep search” // has poor performance. The deep search does as its name implies — searches through all of the tree. For most pages, this will include hundreds of nodes. This slows down the site dramatically.

Try to use the one-child-deep selector ./ where possible.

Remove unused hidden <div>s.

Caching

Enabling caching on your site is a great way to improve performance. Caching is when HTTP responses are stored so that they can be retrieved later. When a requested page is available in the cache, the cached page will be served without having to make an upstream request to the origin server. Since the transformed page will be served from the cache after the initial request, the Moovweb cloud will no longer have to execute Tritium code for subsequent requests. These factors make the page display much faster. Please read the Edge Caching document to learn more about how Moovweb deals with caching.

Test and Repeat

Once you’ve performed the above optimizations, you’ll want to repeat the procedure to test your changes.

Conduct another performance analysis and if there are still areas for improvement, experiment with additional performance optimizations.

Aggressive Optimization Techniques

The following techniques are categorized separately from our standard recommendations because they are more aggressive and as a result have the potential to break the business logic built into your origin site.

These techniques when used properly will yield powerful performance benefits but due to their fragile nature, they should be thoroughly tested before being released into production.

Defer JavaScript

Deferring JavaScript means moving the download and execution of that script to start at the load event. This allows the page to render significantly faster which greatly improves perceived performance.

Insert the following snippet of JavaScript at the top of the <head> element and add the perf.js script to your project’s JavaScript folder.

$("./body") {
  insert("script", type: "text/javascript", src: asset("javascript/perf.js"))
}

perf.js

// JavaScript deferral for external sources
// Add a script element as a child of the body
// Source: https://developers.google.com/speed/docs/best-practices/payload#DeferLoadingJS
function downloadJSAtOnload() {
  console.log("Running JS deferral function");
  var elements = document.getElementsByClassName("mw-defer");
  for(var i = 0; i < elements.length; i++) {
    var element = document.createElement("script");
    element.src = elements[i].getAttribute("src");
    document.body.appendChild(element);
  }
}

// Check for browser support of event handling capability
if (window.addEventListener)
  window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
  window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;

Now any script with the "mw-defer" class will wait until the load event to begin loading.

Mark the scripts you want to defer with the "mw-defer" class and change them to <div> elements so the browser doesn’t begin processing them.

$("//script") {
  match(fetch("@src"), /script1|script2|script3/) {
    name("div")
    add_class("mw-defer")
  }
}

Make sure to test your JavaScript deferral thoroughly. Although it can yield huge performance benefits, it also has a high risk of breaking business logic.