Improved Font Loading

Web fonts are becoming increasingly popular all over the web. Using web fonts allows a site author to include and use specific fonts along with the assets of their websites. Browsers download the fonts with the rest of the site and use them when they finish downloading. Unfortunately, not all web fonts download instantaneously, which means there is some time during the load where the browser must show the webpage without the font. Many web fonts are quite large, causing a long delay until the browser can use them. WebKit has mitigated this in two main areas: improving font download policies, and making fonts download faster.

Default Font Loading Policy

The browser should attempt to show a web page in the best way possible despite not being able to use a font due to an ongoing download. WebKit will always end up using the downloaded font when it is available; however, some fonts may require quite some time to complete downloading. For these fonts, WebKit will show elements with invisible text during the delay. Older versions of WebKit would continue to show this invisible text until the font completes downloading. Instead, newer versions of WebKit will show this invisible text for a maximum of 3 seconds, at which point it will switch to a local font chosen from the element’s style before finally switching to the downloaded font when the download completes.

This new policy minimizes a flash of fallback text for fast-downloading fonts without making long-downloading fonts illegible indefinitely. The best part is that websites don’t have to do anything to adopt this new policy; all font loads will use it by default.

CSS Font Loading API

Different web authors may want different policies for headline fonts or for body fonts. With the CSS Font Loading API, new in WebKit, web authors have complete control over their own font loading policy.

This API exposes two main pieces to JavaScript: the FontFace interface and the FontFaceSet interface. FontFace represents the same concept as a CSS @font-face rule, so it contains information about a font like its url, weight, unicode-range, family, etc. The document’s FontFaceSet contains all the fonts the webpage can use for rendering. Each document has its own FontFaceSet, accessible via document.fonts.

Using these objects to implement a particular font loading policy is straightforward. Once a FontFace has been constructed, the load() method initiates asynchronous downloading of the font data. It returns a Promise that is fulfilled when the download succeeds or rejected when the download fails. By chaining a handler to the returned promise, JavaScript can take action when the download finishes. Therefore, a website could implement a policy of using a fallback font immediately with no timeout by using the following code:

<div id="target" style="font-family: MyFallbackFont;">hamburgefonstiv</div>
let fontFace = new FontFace("MyWebFont", "url('MyWebFont.woff2') format('woff2'),
    url('MyWebFont.woff') format('woff')");
fontFace.load().then(function(loadedFontFace) {
    document.fonts.add(loadedFontFace);
    document.getElementById("target").style.fontFamily = "MyWebFont";
});

In this example, the element is styled declaratively to use MyFallbackFont. Then, JavaScript runs and starts requesting MyWebFont. If the font download is successful, the newly downloaded font is added to the document’s FontFaceSet and the element’s style is modified to use this new font.

WOFF 2

No matter which font loading policy is used, the user’s experience will be best when fonts download quickly. WebKit on macOS Sierra, iOS 10, and GTK supports a new, smaller font file format named “WOFF 2.” The fonts are smaller because they use advanced Brotli compression, which means that WOFF 2 fonts can download significantly faster than the same font represented with other common formats like WOFF, OpenType, and TrueType. WebKit also recognizes the format("woff2") identifier in the src property inside the CSS @font-face rule. Because not all browsers support WOFF 2 yet, it is possible to elegantly fall back to another format if the browser doesn’t support WOFF 2, like so:

@font-face {
    font-family: MyWebFont;
    src: url("MyWebFont.woff2") format("woff2"),
         url("MyWebFont.woff") format("woff");
}

In this example, browsers will use the format CSS function to selectively download whichever fonts they support. Because browsers will prefer fonts appearing earlier in the list over fonts appearing later, browsers encountering this code will always prefer the WOFF 2 font over the WOFF font if they support it.

unicode-range

Bandwidth is expensive (especially to mobile devices), so minimizing or eliminating font downloads is incredibly valuable. WebKit will now honor the unicode-range CSS property for the purposes of font downloading. Consider the following content:

@font-face {
    font-family: MyWebFont;
    src: url("MyWebFont-extended.woff2") format("woff2"),
         url("MyWebFont-extended.woff") format("woff");
    unicode-range: U+110-24F;
}

@font-face {
    font-family: MyWebFont;
    src: url("MyWebFont.woff2") format("woff2"),
         url("MyWebFont.woff") format("woff");
    unicode-range: U+0-FF;
}
<div style="font-family: MyWebFont;">hamburgefonstiv</div>

In this content, none of the characters styled with MyWebFont fall within the unicode-range of the first CSS @font-face rule, which means that there is no reason to download it at all! It’s important to remember, however, that styling any character with a web font will always cause the last matching @font-face to be downloaded in order to correctly size the containing element according to the metrics of the font. Therefore, the most-common CSS @font-face rule should be listed last. Using unicode-range to partition fonts can eliminate font downloads entirely, thereby saving your users’ bandwidth and battery.

Using these techniques can dramatically improve users’ experiences on your website when using web fonts. For more information, contact me at @Litherum, or Jonathan Davis, Apple’s Web Technologies Evangelist, at @jonathandavis or web-evangelist@apple.com.