Using web fonts, the best way (for 2015)

Original author: Anselm Hannemann
  • Transfer
I recently researched the issue of font downloads again, since I wanted to use a local copy of the font and make it load as fast and efficient as possible. This approach is significantly different from when you use TypeKit or Google fonts and simple copy / paste snippets.

Over the past months, several articles have been written addressing the issue of various font loading optimization techniques.

1 , 2 , 3

After I read them all, I found a few new questions that are not addressed in them. In the end, I wanted to have one resource on which information about such problems would be collected. Some code snippets are taken or adapted from articles, the links to which I cited above.

Objectives:

  1. Download web fonts asynchronously
  2. Avoid strong recalculations in layout
  3. Download web fonts as quickly as possible
  4. Avoid font downloads for returning visitors


And now let's try to achieve our goals in stages:

1. Asynchronous download of web fonts


Since you need to call the web font locally via @ font-face, you usually get a blocking request. To avoid it, you need to put the @ font-face code in a separate stylesheet, which is invoked through JavaScript. You can use the simple loadCSS function from filamentgroup. This is the easiest option.

You can also use typekit’s webfontloader with custom web fonts, which, starting with version 1.6.8, use the native font download API, if available.

At the moment, we also have a Font Face Observer , and also a Font Loader , which uses the latest W3C font loading events, and we also have a scriptthat uses Smashing Magazine, and which essentially solves a few more problems in this article (but not all).

So where do we start? To begin with, we will exclude Font Loader, providing a polyfill for the latest web standard. It is too large to be included in this part of the performance optimization phase. In the future, it will definitely be needed, but if it is not “native”, at the moment there is no point in using it. Instead, we can use the Font Face Observer. It weighs only 5Kb (it is reduced, not compressed).

Ok, let's get started. You can get the Font Face Observer script through npm, bower or git (hub). Include the script in head.

Note: Customizing the async attribute adds an unwanted FOIT to the FOUT on your site.

Now we need to initialize the font browser. This can be done using the built-in script, or an external script included in the head. I will show an example that uses the browserify / CommonJS option in an external script, and the script is loaded as an npm dependency:

First we need to request the library:

    var FontFaceObserver = require('fontfaceobserver');


Now let's define the fonts and font options that we need to identify:

    var observer = new FontFaceObserver('Fira Sans', {
        weight: 400
    });


Here, as options, you can use weight, style, variant, featureSettings, stretch. Now we need to initialize Observer to configure the fonts we defined. We also need to set the CSS class into which the font was loaded. This is done through Promise:

    observer.check().then(function () {
        document.documentElement.classList.add('webfont-loaded');
    }, function () {
        console.info('Web font could not be loaded in time. Falling back to system fonts.');
    });


A more advanced example with multiple web fonts:
    var fontfaceobserver = require('fontfaceobserver');
    var fontObservers = [];
    var fontFamilies = {
        'Fira Sans': [
            {
                weight: 400
            },
            {
                weight: 600
            }
        ],
        'Fira Mono': [
            {
                weight: 400
            }
        ]
    }
    Object.keys(fontFamilies).forEach(function(family) {
        fontObservers.push(fontFamilies[family].map(function(config) {
            return new FontFaceObserver(family, config).check()
        }));
    });
    Promise.all(fontObservers)
        .then(function() {
            document.documentElement.classList.add('webfont-loaded');
        }, function() {
            console.info('Web fonts could not be loaded in time. Falling back to system fonts.');
    });



So we applied the Font Face Observer and set the finished font class. Now we need to reflect this in our CSS:

    body {
        font-family: sans-serif;
    }
    .webfont-loaded body {
        font-family: 'Fira Sans', sans-serif;
    }


2. Eliminate a strong recalculation of the layout


Now we have an effective and reliable system in which it will be possible to embed our web font when it is ready. This, of course, means that initially users will receive the transitional font you define. Despite the fact that this is not bad, as they may already begin to read the text, this means that everything will change before their eyes, which often leads to the displacement of words due to a change in the font.

We need to make the experience more enjoyable. This can be done in two stages:

  1. First you need to find the best transitional fonts for your web font. This can best be done with this small bookmarklet and thiscompatibility checks. When you find a good transitional font, half the job is done. But there is not a single font that looks the same, and even very similar transitional fonts can have characters of different widths and heights. Fortunately, CSS has several tools to optimize this. There is a new font-size-adjust property that allows you to adjust the transitional font to your web font or vice versa. Use it to adjust height or shape. It is quite difficult to use, so I recommend trying out some of the values ​​in dev tools (or look at the formula in the article I linked to if you understand the math well). Typically, the result is a value between 0.40 and 0.70.
  2. After selecting the height, you need to configure letter-spacing (the distance between the letters). This is relatively simple, and if you adjust the value in small increments (for example, -0.01em), you can guarantee that the text will look good and readable. At this point, you should get a transition font visualization very similar to a web font. In order to feel the difference during testing, you can add a timeout to the function that sets the CSS class for webfont-loaded.


3. Fastest download of web fonts


This item is pretty simple. In fact, we have already done a lot to ensure that our web fonts load as quickly as possible and turn on at the right time. The last thing we can do here is add a preload header for web font files.



As you can see, here I used only woff fonts. This is because here we should not call all formats. This small snippet tells the browser that, if possible, it should download these resources. If you add all the formats here, the browser will download them all, which is useless. However, all browsers that support prefetch also support WOFF. If you want to use woff2, keep in mind that it no longer works, so you should avoid adding these headers.

4. Font download exception for returning visitors


To eliminate the situation when users reload web fonts and do not run the latest version of JavaScript Font Face Observer, when the font is already accessible from the cache, you can use cookies or localStorage. If, using cookies, you only check if this font is in the browser cache, then localStorage puts the fonts for longer storage in localStorage and takes them out if the user visits the site again.

I will not give preference to anyone, as both options have their advantages. Although localStorage is more reliable in terms of font caching, it is slightly slower than cookies and the browser’s native cache. Use what you like best and what will work better in your project.

Use of cookies :

This method is a little unreliable. The browser’s cache is not directly related to the cookie’s storage location, so if one of them (but not both) is deleted, this method can lead to blocking the font download.

The simplest code using SSI would look like this:



Using localStorage: You can take advantage of this version of the code that Smashing Magazine uses on its site.

Despite the fact that localStorage works pretty well, it is worth considering that its use may be slightly slower than using the native cache, and, more importantly, it takes up space on the user's disk and is created for only one domain. Therefore, if a user visits another site with the same web font, UA will download it again.

What's next?


As we have seen in recent months and years, the way we use web fonts is changing all the time. Browsers use Font Load Events, and even CSS properties can be used to help work with FOIT. Ultimately, font-rendering, font-rendering: swap can greatly simplify everything that I described in this article.

If you want to save a few bytes by excluding some styles or saturation options, you can try to customize the behavior of the browser if artificial fonts are allowed in it and there is no font-synthesis.




Also popular now: