brought to you by REVSYS

Front End Performance

Oh the wifi inside is frightful,

But the content is so delightful,
And since we've no place to go,

Let It Flow! Let It Flow! Let It Flow!
2400 baud's rendition of Let It Snow!

The holidays are a time for being thankful and forgiving the things that bug us. But we can't bring ourselves to forgive this particular trespass, because it's so damn easy to fix. If you don't fix these things about your sites, we'll be putting coal in your stocking.

Less is More

The rules for front end performance boil down to this:

Deliver smaller content and in ways that reduce the work the browser has to do.

Simple right? So how do we do that? Here is the TL;DR version:

  • Users can feel 100ms of performance difference. Small things add up.
  • Don't download things twice
  • Reduce the size of your markup, CSS, and Javascript as much as possible
  • Combine CSS and JS into as few files as possible
  • Deliver it over an optimal number of connections
  • Compress it whenever possible over the wire
  • Optimize your images
  • Use the fastest selectors
  • Make the page redraw as little as possible

Far Future Expires Headers

Great we've finally loaded up your big bloated home page with the sole intention of clicking your 'Contact Us' link. When we do, because your boss is Ebenezer Scrooge and he wouldn't let the developers put some extra coal in the fire, our browser is treated to having to ask if any of the 412 CSS and JS files on your site that we JUST LOADED 2 SECONDS AGO has changed.

Just think of the trillions of wasted bits every day. Poor bits. Don't be that guy.

See each external resource you load is another thing the browser needs to check on to see if there has been an update. So it does a HEAD request back to your server to look at the Last-Modified header. It then compares that time to the time it grabed it last and put it into the browser cache.

On mostly dynamic sites, this is the worst because the last modified time is often right now so it's always changing even if the content actually isn't.

However, if we simply tell the browser to chill out we can drastically improve the perceived performance of your pages. We do this by setting what are often called 'Far Future Expires Headers' or just 'Far Future Headers'.

We do this by setting Expires and Cache-Control headers to some date/time into the future. The longer the better, but even short amounts help.

Assuming we have our static assets like our logo, CSS, and JS in /static/, we add this to nginx:

location /static/ {
    alias /home/our-site/public_html/static/;
    expires 1h;
}

Now, after we've loaded up your big slow resources we at least don't have to check on them again for the next hour. This removes an entirely unnecessary HEAD request for each and every resource on your page. While they're pretty speedy, the browser does have to wait for them all to complete before rendering your inner page.

Remember kids, HEAD requests aren't free.

"But I need my lovely changes to take effect immediately", you say. Well I asked Santa and he said that's bullshit.

That bug was there for the last week/month/year, the fix can wait another hour. Maybe you're doing a whole site redesign and your old CSS is going to severely break the page. Awesome when exactly was the last time you did that? 2013? You can change the file names of your resources and boom, problem solved. More on that below. Remember, we're optimizing for the browser here, not your lazy need to always have CSS which you change rarely, named 'styles.css'.

Reducing the size of your resources

First tip, don't load things you don't need. You likely quit using that one Google Font months ago, but are still telling your customers to download it. Quit that.

If you have a few pages or sections of your site that use larger resources, only load those for those pages. However, common items like your main CSS and JS should be loaded site wide even if not ALL of it is being used on every page. Remember, we want to reduce the number of resources we're downloading.

This is especially true for mobile users where making another request is orders of magnitude slower than when you're at the office on something like Google Fiber.

So else can we reduce the size of our resources? Compression for one. 99.99% of browser support gzip/deflate, start using it. For nginx the setup is like this:

gzip on;
gzip_disable "msie6";
gzip_min_length 1000;
gzip_http_version 1.0;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

Seriously this turns a 133KB CSS file on one of our sites into a 27KB download.

Reduce the size of your CSS

If you're using a CSS framework like Bootstrap or Foundation often your site is only using a fraction of the styles in there. It's easy to just load up the whole thing, but you can often shave 50-100K off the size of these frameworks by customizing them down to just the parts you're actually going to use. Sure it takes a few minutes of your time, but saves every user of your site some time. Both have customized download pages or you can only import the portions you're using in your sass or less configs.

Reduce the size of your images

This can be a big win, especially for your mobile users. We're talking in KBs here.

There are lots of options here. The simplest is turning down the quality setting in Photoshop or your thumbnailing tool chain until you can't see a perceptible difference. You might piss off a few Retina users, but your mobile ones will thank you.

Many people however are not aware there are lossless options available. Simply running your images through tools like these can reduce file sizes. We've seen results from 5-50% depending on the image and format. Be sure to check out:

For thumbnailing, there are lots of different options. Our personal favorite for Django is django-imagekit. Keep in mind, it's common to have dozens of thumbnails on list pages so reducing each thumbs file size multiplies the win.

Combine your CSS and JS

You've got your CSS and JS separated out into dozens of files. This makes your life easier, your code base more modular and easier to understand. We get that. But it makes the browser work harder. Combine them into fewer files for production use.

How you do that depends on your toolchain. If you're using Django check out django-compressor or django-pipeline

Another option is to use gulp and gulp-concat to do the work for you. Here's a write up on how to concatenate all of your CSS files with gulp.

With these tool chains you can also do something nifty. You can have them store the files named with a hash of the underlying components. This let's you put REAL Far Future Headers on them, I'm talking like expring them in a year. Then when you change that one line of CSS, it can go out and into production immediately. It will have a new name, all of your user's browsers will download the new version and keep it in their cache until the next change you make.

Use Faster Selectors

The selectors you use in your CSS and JS can make a big difference. Read up on this and just get in the habit of using the right selector for the right job. It's often a micro-optimization on most sites, but why keep the bad habit of using slow stuff when there isn't a downside to learning a better way?

Use Faster Javascript

Do you have pages and pages of jQuery code? Are you making hundreds of decisions about what should be shown/hidden, adding/removing classes, etc? It might be time to rethink your approach.

The browser is having to do a lot of work traversing the DOM looking for the bits that match your selectors. Then changing the DOM. Then repainting the page. There are lots of ways to reduce this work, faster selectors from above being one. However, at a certain point you can't go much further.

Enter ReactJS. It builds your DOM elements for you and keeps track of the state of things. Then, when the situation/data changes, it makes your changes. It does this by using a Virtual DOM and calculating the least number of DOM changes to implement what needs to happen. We're big fans and have seen it drastically improve the perceived speed of Javascript heavy pages.

Naughty or Nice?

So which is it going to be? Are you going to get onto the RevSys list of nice fast sites or the naughty list? If you choose the later, we suppose the one benefit of getting coal for Christmas is you can use it to help power the steam engine you likely are still using to get to work.

But seriously, none of these changes are hard or seriously work flow altering. We hope you choose to give YOUR USERS the gift of better performance this holiday season!