Delivering Web Fonts

Before delving into the typographic details, let’s take a look at ways to deliver fonts to your web page. Using the @font-face rule, you can host fonts on your own server. Here is the basic CSS syntax:

	
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400;
    src:
      url('lora-regular.woff2') format('woff2'),
      url('lora-regular.woff') format('woff'),
      url('lora-regular.ttf') format('truetype');
}
	

First, the font-family property declares the name of the typeface. Next, the font-style specifies the style (normal or italic) and the font-weight defines the boldness (100900) of your fonts. Lastly, the src property, which instructs the browser the location of the fonts, has two elements: the url provides the path to the font files and the format is present to support specific browsers. For example, woff2 format is supported only in Chrome and Opera. Both woff and truetype are supported in almost all browsers. Because woff2 provides 30% reduction in file size, it is listed first in the stack. On the other hand, truetype has the widest support (even in older browsers); therefore, it is listed last in the stack. To learn more about font format, read Ilya Grigorik’s “Webfont Optimization.”

Web Font Services

Although you can use the @font-face rule to host fonts on your own server, one of the advantages of using web font services like Google Fonts and Typekit is that they take care of all the work behind the scenes. You don’t need to worry about font optimization, browser compatibility, reliable performance, and licensing agreements. Here is an example of loading fonts from Google using one line of code—the link element:

<link href='http://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>

If you use Typekit, here is the code you will need:

<script src="//use.typekit.net/XXXXXXX.js"></script>
<script>try{Typekit.load({ async: true });}catch(e){}</script>

That’s it. You can then refer to the custom fonts in CSS like any other fonts.

Web Font Loader

The one-line link element is the simplest solution to web font delivery, but it is not the ideal method. Because font styles are referenced in the head of the page, they must be downloaded before they can be displayed. In most browsers such as Chrome, Firefox, Opera, and Safari, text won’t render (up to three seconds) until custom fonts are loaded. As a result, users could experience a flash of invisible text (FOIT). In iOS Safari, users could see a blank page up to thirty seconds, depending on the speed of their internet connection and the size of the site’s custom fonts. Internet Explorer is the only browser that displays the fallback type first and then switches to custom type once the font assets finish loading. The result is that users could experience a glaring flash of unstyled text (FOUT).

To provide an optimal experience across modern browsers, using the Web Font Loader to deliver fonts asynchronously—the JavaScript method of scheduling actions to load only what needed at the moment—is recommended. Users may see FOUT the first time they visit the site, but their experience won’t be interrupted once the font assets are downloaded and cached. The Web Font Loader is a JavaScript library co-developed by Google and Typekit, but it can load fonts from other services including Fonts.com and Fontdeck. To load Google fonts asynchronously via Web Font Loader, use the following code:

	
<script type="text/javascript">
  WebFontConfig = {
    google: { families: [ 'Lora:400,700,400italic,700italic:latin' ] }
  };
  (function() {
    var wf = document.createElement('script');
    wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
      '://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
    wf.type = 'text/javascript';
    wf.async = 'true';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);
  })(); </script>

<noscript>
  <link href='http://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
</noscript>

The code in between the script tags executes asynchronously to avoid blocking the rendering of the page. The link element wrapped inside the noscript tags is included to ensure that custom fonts will still be available if JavaScript is turned off or fails to load.

Because asynchrony is set to true (wf.async = 'true';), FOUT can occur. If the x-height in the fallback fonts is drastically different from the custom fonts, the FOUT effect can disrupt the flow of reading. To make the FOUT less glaring for users, you can use CSS to style the fallback fonts to match the size of the custom fonts. The Web Font Loader provides three CSS classes: .wf-loading (before custom fonts are loaded), .wf-active (after custom fonts are loaded), and .wf-inactive (if custom fonts failed to load). Here is an example of styling fallback fonts:

	
.wf-loading p {
  /* styles for fallback fonts */
}

.wf-active p {
  /* styles for custom fonts */
}

.wf-inactive p {
  /* use fallback fonts */
}	
	

To learn more about the Web Font Loader, check out the documentation and source code on Github.

Font Face Observer

While Web Font Loader solves the FOIT issue, it still has the blink effect when custom fonts swap out the system fonts, particularly when users refresh the browser. In addition, the Web Font Loader JavaScript library needs to be referenced at the top of the document, which adds extra overhead. Font Face Observer, a fairly new delivery mechanism developed by Adobe Typekit engineer Bram Stein, uses JavaScript’s scroll events to load and monitor web fonts. Unlike the Web Font Loader, the Font Face Observer can be referenced at the end of document to avoid the extra overhead. According to Scott Jehl, a developer with expertise in web performance, Font Face Observer is the fastest delivery mechanism as of this writing. Here is the markup adapted from Jehl’s method of using the Font Face Observer:

	
<!DOCTYPE html>
<!--#if expr="$HTTP_COOKIE=/fonts\-loaded\=true/" -->
<html lang="en" class="fonts-loaded">
<!--#else -->
<html lang="en">
<!--#endif -->
<head>
  <meta charset="utf-8">
  <title></title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
  @font-face {
    font-family: 'Lora';
      src: url('lora-regular.woff2') format('woff2'),
           url('lora-regular.woff') format('woff'),
           url('lora-regular.ttf') format('truetype');
    font-weight: 400;
    font-style: normal;
	}
  @font-face {
    font-family: 'Lora';
      src: url('lora-italic.woff2') format('woff2'),
           url('lora-italic.woff') format('woff'),
           url('lora-italic.ttf') format('truetype');
    font-weight: 400;
    font-style: italic;
    }
    body {
        font-family: serif;
    }
    .fonts-loaded body {
        font-family: Lora, serif;
    }
    </style>
</head>
<body>
    <p><!-- paragraph text --></p>
    <script src="fontfaceobserver.js"></script>
    <script>
    (function( w ){
    if( w.document.documentElement.className.indexOf( "fonts-loaded" ) > -1 ){
        return;
    }
    var font1 = new w.FontFaceObserver( "Lora", {
        weight: 400
    });
    var font2 = new w.FontFaceObserver( "Lora", {
        weight: 400,
        style: "italic"
    });
    w.Promise
        .all([font1.check(), font2.check()])
        .then(function(){
            w.document.documentElement.className += " fonts-loaded";
        });
    }( this ));
    </script>
</body>
</html>
	

In the code above, you begin with setting a cookie to check if the custom fonts have loaded before. With subsequent visits after the initial loading, the fonts are cached in the browser; therefore, you want to add the fonts-loaded class upfront using SSI (server side includes):

	
<!--#if expr="$HTTP_COOKIE=/fonts\-loaded\=true/" -->
<html lang="en" class="fonts-loaded">
<!--#else -->
<html lang="en">
<!--#endif -->
	

For a quick tutorial on SSI, read Joe Burns’s “SSI: The Include Command.”

Next, you simply use @font-face rule in your CSS to load custom fonts. Referencing your fonts right in the page rather than in an external style sheet speeds up loading time. The browser doesn’t have to make an extra request to an external file.

After that, you declare the system fallback fonts for the body and the fonts-loaded to swap out once the custom fonts are loaded:

	
body {font-family: serif;}
.fonts-loaded body {font-family: Lora, serif;}
	

Then near the end of the page (before the </body> tag), you want to call the Font Face Observer:

	
<script src="fontfaceobserver.js"></script>
	

Finally, the following function uses the check() method to see when the fonts are finished loading and uses the then() method to add the fonts-loaded class into your HTML:

	
w.Promise
  .all([font1.check(), font2.check()])
  .then(function(){
    w.document.documentElement.className += " fonts-loaded";
  });
	

To learn more about Jehl’s approach, read his article on the Filament Group’s blog.

The code just to get the fonts to load on your page might seem overwhelming, but you just need to be aware of the various options. The method you choose depends on your level of web development. Use the one that makes you feel most comfortable. In the proceeding chapters, I will be using the basic delivery to keep the demos simple. If you want to nerd out, however, read Zach Leatherman’s “A Comprehensive Guide to Font Loading Strategies.”