The last time Hackerfall tried to access this page, it returned a not found error. A cached version of the page is below, or clickhereto continue anyway

Hacking Your Webpage's Head Tags for Speed and Profit

Hacking Your Webpage's Head Tags for Speed and Profit

Summary: One of the most important parts of any webpage's performance is the content and organization of the head element. We'll take a deep dive on some easy optimizations that can be applied to any site. (2754 words/13 minutes)

"What's that? The site takes 15 seconds to load on mobile? Sorry, but Marketing says I gotta put Mixpanel in here first." Most of us developers settle for page load times somewhere between 3 and 7 seconds. We open up the graph in NewRelic or webpagetest.org, sigh, and then go back to implementing that new feature that the marketing people absolutely must have deployed yesterday.

Little do we realize, perceived front-end load times closer to half a second are possible for most (if not all) websites with very little effort.

Most webpages have slow frontend load times not because they're heavy (north of 1MB), or because they need 200kb of Javascript just to render a "Hello World!" (cough Ember cough). It isn't because the pipes are too small either - bandwidth is really more than sufficient for the Web today.

HTML, TCP and latency are the problems, not bandwidth. Page weight, while important, is a false idol.

A 1MB webpage, with all of it's scripts and CSS inlined, will load faster than 1 MB webpage with 100 different asset requests spread across 10 domains. Each of these asset requests requires a TCP connection, and setting up those connections takes longer when there's more network latency. This is really TCP's fault - it was designed for long, streaming downloads, not the machine-gun fire of 3rd-party Javascript and assets that most websites today require. God forbid you're in a high-latency environment too, like a mobile connection or a developing country. When latency starts to shoot north of 100 milliseconds, webpages grind to a halt trying to set up dozens of three-way handshakes to download all of the cat gifs your social media intern said would totally blow up this blog post on Reddit.

In addition, some quirks in how HTML works means that certain subresources 11 Sub-resource is a fancy word for another the HTML document needs - images, stylesheets, fonts, scripts, video and audio are all subresources. must block page rendering - leaving the browser idling, waiting for things to download and execute. Preventing (and dealing with) the various types of blocking that can happen during a webpage load presents a major performance opportunity. The problem of webpage loading is generally not a problem of resources, it's a problem of using those resources efficiently so that they don't block each other's execution.

Thankfully, humans are squishy, and perceived load times are not the same as window load times. We can hack our user's perceptions to make them think the webpage loaded faster than it did. window.load, while a good starter metric for measuring page load speed, is not a realistic interpretation of how users look at webpages. Humans (unlike computers) can begin to understand the webpage before it's even finished completely loading. This means that time to paint, not time to load is important. In addition, time to paint the page's usable content is of course the most important thing. Gmail quickly paints a loading bar, sure, but you didn't come to Gmail to see the loading bar. You came to see the application. Likewise, if our news website paints some divs to the page but doesn't actually show any text until 2 seconds later because the web fonts took forever to load, then the site wasn't really usable until that text was painted. Thankfully, it's easier to decrease perceived load times than it is to decrease total load time (as measured by window.load). Amazon, for example, paints a nearly complete page just 1.5 seconds after a request is sent, but window.load doesn't fire until 3.5 seconds later.

We can leverage human perception to disproportionately affect perceived load times with minimal effort. And the place these opportunities can be exploited is in a site's head tag.

The head tag is probably the most important part of any webpage from a performance standpoint. It can truly make or break a speedy page - two identical head tags with different element ordering can have speed differences on an order of magnitude, especially in poor network conditions (like mobile or the developing world). But sometimes optimizing head tags can be confusing - there's a lot to understand and browser technology changes rapidly, meaning yesterday's advice can be out of date.

In this article, I'll attempt to show what the optimal head tag looks like - what elements in contains, in what order, and with what special attributes (such as async and defer) that will lead to zippy-quick load times.

First, some definitions. What exactly are we going to optimize for?

When thinking about page load optimization, there are usually three important times for the end user:

Our optimal head tag will try to optimize all of these times. It's important to note that often you'll be presented with a tradeoff - you can decrease time to first paint by increasing time to load, and vice versa. I'm going to point out these tradeoffs, but generally I'm going to prefer to decrease time to first text paint.

Encoding

"You get used to it. I don't even see the code anymore. All I see is cat gif, BuzzFeed listicle, Facebook status..." Here's an easy optimization to start us off. When a browser downloads your page off the network, it's just a stream of bits and bytes, and the browser doesn't really know what character encoding you used. Before it can read the data, it needs to decide on a character encoding to use to read the document. 99.9% of the time on the web, we do this with UTF-8, but that isn't guaranteed.

The browser has to decide what character encoding to use. There's a couple of ways it can do this (fastest first):

X-UA-Compatible is very similar to character encoding - we want as high up in the document as possible because if you specify a value that's different than what the browser is already using to parse the document, you'll restart the rendering process. If you have to specify a X-UA-Compatible value, here's some tips:

Viewports

Here's another one. If you're going to specify a viewport size, do it at the very top of the head.

Why?

Browsers translate this:

<meta name="viewport" content="width=device-width, initial-scale=1">

...into this:

<style>
@viewport {
  zoom: 1.0;
  width: device-width;
}
</style>

While the spec for how this works is still unfinished, you can bet that most browsers already implement it this way.

There's a problem with this - if you put the viewport meta tag after your stylesheets, you will cause a layout reflow for the entire document, slowing down rendering. Don't do that. Keep your viewport tags at the top, right after your character encoding. In addition, putting a viewport tag at the bottom of the head will almost certainly cause a "flash of unstyled content" as the CSS is first loaded in the default viewport, then re-rendered in your specified viewport.

Concatenation of Assets

TCP isn't really designed for short bursts. It's got a load of overhead, and needs a lot of back-and-forth just to set up a connection.

Despite this, the top 1000 websites in the world on average require 31-40 TCP connections. I'm sure all of them are important, and aren't advertisements, creepy 3rd-party trackers, or bloatware! Surely, all of those requests are for absolutely necessary subresources and not a single one could be eliminated.

Alright, jokes aside, here's the scoop. Opening a new TCP connection is slow - it's especially slow if you're asking for content from a different domain (you might need to resolve DNS, negotiate TLS, and more). Minimize new connections where you can. One of the easiest places to do this is by concatenating your assets.

Although the Rails asset pipeline has been a constant source of headache for beginner Rails developers, it is absolutely one of the best performance optimizations that the framework provides.

Concatenate all of your site's stylesheets and scripts into one file each. It's 2015. There's no excuse. 22 Yes, I know all of this will change when HTTP2 becomes widespread. But it isn't yet, and might not be for at least another year or two. If you're living a magical fairy land where you already get to use HTTP2 in production, go read someone else's guide on that.

If you've got a lot of images, it may be time to start thinking about image sprites or an icon font.

All of this can be benchmarked in the wonderful Chrome Network tab - try different configurations and watch the results.

Async Defer

I'm a Ruby guy, but I hear those Javascript people talking about "async" stuff a lot. It seems like the cool thing these days - everything is "asynchronous" and "non-blocking"! But I live in Ruby land, and most things in our applications are synchronous and blocking. Gee, thanks GIL.

Ordinarily, script tags with an external src attribute (that is, not inlined) are synchronous and blocking too.

<script type="text/javascript" src="//some.shitty.thirdpartymarketingsite.com/craptracker.js"></script>

When this tag is in the head, the browser cannot proceed with rendering the page until it has downloaded and executed the script. This can be very slow, and even if it isn't, if you do it 6-12 times on one page it will be slow anyway (thanks TCP!). Here's an example you can test in your own browser. Ouch, right? 33 While the browser cannot proceed with rendering the page (and therefore painting anything to the screen) until it's finished executing the script, it CAN download other resources further on in the document. This is accomplished with the browser preloader, something I'll get in to next week.

You may be thinking this is rather ridiculous - why should a browser stop completely when it sees an external script tag? Well, thanks to The Power of Javascript, that external script tag could potentially wreak havoc on the document if it wanted. Heck, it could completely erase the entire document and start over with document.write(). The browser just doesn't know. So rather than keep moving, it has to wait, download, and execute. 44 All in the HTML spec.

However, in the world of front-end performance, I'm not so restricted! This is not the only way! There's an async attribute that can be added to any script tag, like so:

<script type="text/javascript" async src="//some.shitty.thirdpartymarketingsite.com/craptracker.js"></script>

And bam! instantly that entire Javascript file is made magically asynchronous right?

Well, no.

The async tag just tells the browser that this particular script isn't required to render the page. This is perfect for most 3rd-party marketing scripts, like Google Analytics or Gaug.es. In addition, if you're really good (and you're not a Javascript single-page-app), you may be able to make every single external script on your page async.

async downloads the script file without stoppping parsing of the document - the script tag is no longer synchronous with the

There's also this defer attribute, which has slightly different effects. What you need to know is that Internet Explorer 9 and below doesn't support async, but it does support defer, which provides a similar functionality. It never hurts to just add the defer attribute after async, like so:

<script type="text/javascript" async defer src="//some.shitty.thirdpartymarketingsite.com/craptracker.js"></script>

That way IE9 and below will use defer, and everyone who's using a browser from after the Cold War will use async.

Here's a great visual explanation of the differences between async and defer.

So add async defer to every script tag that isn't required for the page to render. 55 The caveat is that there's no guarantee as to the order that these scripts will be evaluated in when using async, or even when they'll be evaluated. Even defer, which is supposed to execute scripts in order, sometimes won't (bugs, yay). Async is hard.

Stylesheets first

You may have a few non-async script tags remaining at this point. Webfont loaders, like Typekit, are a common one - we need fonts to render the page. Some really intense marketing JS, like Optimizely, should probably be loaded before the page renders to avoid any flashes of unstyled content as well.

Put any CSS before these blocking script tags.

   <head>
     <link rel="stylesheet" media="screen" href="/assets/application.css">
     <script src="//use.typekit.net/abcde.js" type="text/javascript"></script>

There's no async for stylesheets. This makes sense - we need stylesheets to render the page. But if we put CSS (external or inlined) after an external, blocking script, the browser can't use it to render the page until that external script has been downloaded and executed.

This may cause flashes of unstyled content. The most common case is the one I gave above - web fonts. A great way to manage this is with CSS classes. While loading web fonts with Javascript, TypeKit (and many other font loaders) apply a CSS class to the body called wf-loading. When the fonts are done loading, it changes to wf-active. So with CSS rules like the below, we can hide the text on the page until we've finished loading fonts:

.wf-loading p {
  visibility: hidden
}

While text is the most important part of a webpage, it's better to show some of the page (content blocks, images, background styles) than none of it (which is what happens when your external scripts come before your CSS).

Conclusion

To wrap up my recommendations from this article:

Next week, I'll be covering even more ways to speed up page loads by optimizing your head tag. We'll cover browser preloaders, HTTP caching, resource hints, streaming responses, and < 4KB headers.

Want a faster website?

I'm Nate Berkopec (@nateberkopec). I write online about web performance from a full-stack developer's perspective. I primarily write about frontend performance and Ruby backends. If you liked this article and want to hear about the next one, click below. I don't spam - you'll receive about 1 email per week. It's all low-key, straight from me.

Now Available: The Complete Guide to Rails Performance

I've authored an in-depth course for making Ruby and Rails applications faster. The Complete Guide to Rails Performance is a full-stack course that gives you the tools to make Ruby on Rails applications faster, more scalable, and simpler to maintain. It includes a 361 page PDF and over 15 hours of video content.

Learn more at railsspeed.com.

Continue reading on www.nateberkopec.com