Loading Typekit fonts asynchronously

Update: We now offer an official asynchronous embed code through the Kit Editor, so you no longer have to create your own. Details are available in this blog post.

The standard Typekit embed code has many advantages. It’s simple, compact, very easy to implement, and automatically helps to prevent the flash of unstyled text (or FOUT). These advantages make it the right choice for the vast majority of sites.

The asynchronous loading patterns that we’ll discuss in this post provide a useful alternative in situations where you must eliminate any possibility that a problem loading the kit could interfere with loading the rest of the page. Asynchronous patterns are longer, more difficult to implement, and require extra work to avoid the FOUT. But these approaches ensure that your page won’t wait for the kit in the unlikely event that something goes wrong somewhere between the font network and the user.

In fact, we use the font events asynchronous pattern described below on the Typekit status blog to ensure that our users can reliably read about our system status, even during a font network outage or degradation.

Standard Typekit embed code

Before discussing asynchronous loading patterns, let’s take a detailed look at what happens when using the standard Typekit embed code. This will help to frame the differences between the standard embed code and asynchronous patterns.

When a web browser parses and renders a web page, a <script> tag will block the rendering of elements and the execution of scripts further down the page. This is because web browsers use a single-threaded model when executing JavaScript. The script that’s executing could use document.write() to alter the page, or trigger a redirect to go to a different page entirely. Because the browser doesn’t know what executing the script will do, it waits until the script is done loading and executing before moving on. Modern browsers continue downloading other resources on the page while the script is executing, while older browsers put a hold on that too.

Typekit’s standard embed code is just a simple pair of <script> tags. The first is an external <script> tag that loads the kit JavaScript from our content delivery network (or CDN). The second <script> tag is a piece of inline JavaScript that actually kicks off font loading using the kit.

<script type="text/javascript" src="//use.typekit.net/abc1def.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>

This standard embed code takes advantage of the fact that <script> tags block further rendering of the page to help prevent the FOUT. While the Typekit script is loading, rendering of the page is blocked, so text won’t start to render with fallback fonts. Once the script has finished loading and executing, the FOUT can be controlled with font events, as we’ve discussed in a previous post.

Normally, this works great, but the downside of this approach becomes apparent in the rare event that the Typekit script takes too long to load. What was once a desirable delay in rendering to hide the FOUT becomes a serious problem when the script takes longer than a few seconds to load. The page will fail to render as long as the request for the kit fails to return a response. We labor tirelessly to make sure that this never happens, working with our CDN partner to ensure that kits are delivered in a reliable and timely manner around the world. Unfortunately, it’s impossible to forsee and prevent every outage, network problem, and user configuration issue.

If this failure mode, however unlikely, is an unacceptable risk for your project, you should consider using one of the following asynchronous patterns instead. Asynchronous patterns don’t block rendering of the page while the fonts load, which means that the FOUT must be dealt with via other means.

Standard asynchronous pattern

This first pattern is the most basic. It’s based on patterns written about by web performance experts like Steve Souders and used in other JavaScript embed codes like Google Analytics.

<script type="text/javascript">
  (function() {
    var config = {
      kitId: 'abc1def'
    };
    var d = false;
    var tk = document.createElement('script');
    tk.src = '//use.typekit.net/' + config.kitId + '.js';
    tk.type = 'text/javascript';
    tk.async = 'true';
    tk.onload = tk.onreadystatechange = function() {
      var rs = this.readyState;
      if (d || rs && rs != 'complete' && rs != 'loaded') return;
      d = true;
      try { Typekit.load(config); } catch (e) {}
    };
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(tk, s);
  })();
</script>

This pattern uses a single inline <script> tag to dynamically add a new script element to the page, which loads the kit without blocking further rendering. An event listener is attached that calls Typekit.load() once the script has finished loading.

How to use it:

  • Place this snippet at the top of the <head> so the download starts as soon as possible.
  • Edit the highlighted config object and replace the default with your own Kit ID.
  • You can add JavaScript font event callbacks to the config object.

Advantages:

  • Loads the kit asynchronously (doesn’t block further page rendering while it loads).

Disadvantages:

  • Adds more bytes to your html page than the standard Typekit embed code.
  • Causes an initial FOUT in all browsers that can’t be controlled or hidden with font events.

Font events asynchronous pattern

When using the standard asynchronous pattern, the inability to hide the initial FOUT with font events while the kit JavaScript loads is a serious drawback that might be a dealbreaker. This next pattern builds on the standard pattern, but adds the ability to control the initial FOUT with font events.

<script type="text/javascript">
  (function() {
    var config = {
      kitId: 'abc1def',
      scriptTimeout: 3000
    };
    var h = document.getElementsByTagName('html')[0];
    h.className += ' wf-loading';
    var t = setTimeout(function() {
      h.className = h.className.replace(/(\s|^)wf-loading(\s|$)/g, ' ');
      h.className += ' wf-inactive';
    }, config.scriptTimeout);
    var d = false;
    var tk = document.createElement('script');
    tk.src = '//use.typekit.net/' + config.kitId + '.js';
    tk.type = 'text/javascript';
    tk.async = 'true';
    tk.onload = tk.onreadystatechange = function() {
      var rs = this.readyState;
      if (d || rs && rs != 'complete' && rs != 'loaded') return;
      d = true;
      clearTimeout(t);
      try { Typekit.load(config); } catch (e) {}
    };
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(tk, s);
  })();
</script>

This pattern uses the same basic approach as the standard pattern, but adds additional JavaScript that provides basic font event CSS class name support before the kit has even loaded. When the script first executes, the wf-loading font event class name is immediately added to the <html> element. After a configurable timeout, if the script hasn’t yet loaded, wf-loading is replaced with wf-inactive. When the fonts finish loading, wf-inactive will be replaced with wf-active. You can use these class names to hide the initial FOUT by setting visibility: hidden on elements with Typekit fonts while the wf-loading class name is present. For example:

#page-title {
  font-family: proxima-nova-1, proxima-nova-2, sans-serif;
}
.wf-loading #page-title {
  visibility: hidden;
}

How to use it

  • Place this snippet at the top of the <head> so the download starts as soon as possible.
  • Edit the highlighted config object and replace the default with your own Kit ID.
  • Edit the highlighted config object to adjust the number of milliseconds to wait before switching from wf-loading to wf-inactive while loading the script.
  • You can add JavaScript font event callbacks to the config object.

Advantages

  • Loads the kit asynchronously (doesn’t block further page rendering while it loads).
  • Provides font events that allow you to control the initial FOUT while the script loads.

Disadvantages

  • Adds more bytes to your html page than both the standard Typekit embed code and the standard asynchronous pattern.
  • Requires writing additional CSS to hide the initial FOUT in all browsers (as opposed to the standard Typekit embed code, where FOUT is hidden automatically in all but Firefox).

Other patterns

The two patterns discussed above represent the best options we’ve found for loading Typekit fonts asynchronously. We’ve explored a few other patterns as well, but won’t go into detail on them here. They have additional drawbacks and compatibility issues, but they might be useful in certain circumstances.

Standard and font events asynchronous patterns with jQuery

If you’re already using jQuery on your page, you can use jQuery to shorten the amount of JavaScript necessary for both the standard and font event asynchronous patterns discussed above. This reduces the size of your HTML page, but also delays the loading of the Typekit script until the jQuery script can be downloaded, parsed, and executed. You can see the standard jQuery pattern and font events jQuery pattern on GitHub.

Embed code at the bottom of the page

You can prevent the standard Typekit embed code from blocking the initial rendering of your page by placing it at the bottom of the <body> tag instead of in the <head>. While this allows your page to render, it delays the loading of the Typekit script until the entire page is nearly finished parsing. In addition, there’s no way to control the initial FOUT, and this pattern may still block the execution of other JavaScript on the page. You can see the bottom of the body pattern on GitHub.

Script tag with async attribute

Modern browsers allow you to add an async attribute to a <script> tag, which tells the browser to load the script asynchronously and not block the rest of the page. However, older browsers, including IE 6-8, do not support this attribute, nor do they support onload on <script> tags. (The similar defer attribute, which is often used instead of async in older versions of IE, isn’t a good option here because it delays execution of the script until parsing of the page is complete.) The lack of support for this method makes it less useful. You can see the async attribute pattern on GitHub.

On GitHub

All of the async patterns mentioned in this post are available on GitHub as example pages in the typekit-async-patterns repository. You can head over there to see them all together, download the examples and try them out, or even fork the repository and add your own patterns if you’d like to contribute.

4 Responses

  1. Jenn Lukas says:

    Awesomesauce! Thanks for covering more options to tackle this.

  2. Theo says:

    You guys rock! Great tips and things to know!

  3. Ted says:

    Very cool solution.

    I had a question about users who use the noScript plugin for Firefox, and I’m wondering if this might be a partial solution?

    1. Sean McBride says:

      I tested this out, and NoScript blocks JS from untrusted domains regardless of how the JS is loaded, so this approach doesn’t really help with NoScript. Users need to enable scripts from typekit.com and the site before they will run when using NoScript.

Comments are closed.