Font Loading - Web Fonts Performance - Responsive Web Design, Part 2 (2015)

Responsive Web Design, Part 2 (2015)

Web Fonts Performance

Font Loading

You’re probably familiar with the basics of CSS font stacks and fallback fonts: browsers try to load the first font in the stack that matches a given family name, weight, style, and variant. If that isn’t available, it continues with the next fallback font until it finds one that is available.

There’s one caveat here: a browser’s font-matching algorithm will return fonts that match only on family name but not on weight, style, or variant. Consider this scenario: the browser has found a match for family name but not the required variation (bold, bold italic, etc.). Instead of rendering the text in a fallback font the browser will use the variation it already has and attempt to generate the required variation. This is the cause of so-called faux bold, faux italic and faux small caps, also officially known as font synthesis, described in great detail by Laura Franz in her article “Setting Weights And Styles With The @font-face Declaration6”.

Type designers spend a lot of time making beautiful, specialized variations of their typefaces; auto-generated faux variations are less desirable than their designed counterparts. You can avoid this by always including web fonts for all the styles you use on your site. Let’s say your site uses thin, thin italic, thin bold, regular, and bold styles for a web font. In order to avoid faux styles, you must include separate @font-face rules for that particular font for each of those five styles.

Faux styles can occur for both web fonts and locally installed fonts. However, you’re unlikely to see faux styles for locally installed fonts because most installed versions include bold and italic variations by default.

The font fallback mechanism is a bit more complicated than simple selection based on font family, weight, style, and variant. Web browsers also have to take into account that not every font includes all characters. They will need to find fonts that either fully or partially match the character support for a given piece of text.

<p>hello world!</p>

Let’s say you’re using two fonts which each only support a select number of characters. Font A supports the characters “h”, “e”, “l” and “o” and font B supports “w”, “r”, and “d”. The CSS font stack contains both web fonts and the generic sans-serif fallback font.

p {

font-family: A, B, sans-serif;

}

In this seemingly contrived example (which is actually quite common for content written in multiple languages) browsers will use three different fonts — Font A, Font B and the generic sans-serif — to render the “hello world!” string. Sans serif is used because neither Font A nor Font B include the “!” character.

The browser uses three different fonts for a single paragraph because the fonts only contain a limited number of characters
The browser uses three different fonts for a single paragraph because the fonts only contain a limited number of characters.

Using web fonts does not significantly change the fallback mechanism. However, when a font family name is used in a font stack it is first matched against all @font-face rules in the document before the browser will look at local fonts; if a match is found within the document’s @font-face rules, the browser will start downloading the web font. (Older Internet Explorer versions are an exception: they start downloading fonts for all @font-face rules regardless of whether they are used or not.) While fonts are downloading, browsers will not examine other families in the font stack because they need to know which characters are in the web font before they can fall back to other fonts.

This means that browsers will go through the following three steps for each font family name they try to match, before giving up and using a fallback font (which in turn goes through the same steps).

1. The font family matches a @font-face rule, but the font file is not in cache. The font is applied once it is downloaded.

2. The font family matches a @font-face rule, and the font file is cached. The font is applied immediately.

3. The font family matches a locally installed font and is applied immediately.

There are several drawbacks to this mechanism. Browsers need to have enough information from both the CSSOM and the DOM before they can start downloading a web font. The benefit of this approach is that if a web font is not used by any CSS selector that matches an element in the DOM, browsers can prevent unnecessary downloads. In practice, this could very well mean that font downloading is blocked by both your HTML and CSS.

This waterfall chart shows that fonts only start downloading once both the DOM and CSSOM are available, because only at that point do browsers know they need to load web fonts
Fonts only start downloading once both the DOM and CSSOM are available, because only at that point do browsers know they need to load web fonts.

Another drawback is that browsers can only know which characters are included in a font after they have finished downloading it. If a font doesn’t include the characters required to render the content, it will have been downloaded for nothing!

This can be avoided by using the unicode-range property in your @font-face rules. The unicode-range property tells browsers which characters are part of the font so that they can decide whether or not to download the font. If the font supports some of the characters required to render text, browsers will download the font. The font is not downloaded if none of the required characters are listed in its Unicode range. In the upcoming section on subsetting, we’ll take a look at browser support for the unicode-range property and also demonstrate how to exploit it to optimize font downloads.

The final drawback is the amount of time it takes to download a web font compared with locally installed fonts. This is an important difference between locally installed fonts and web fonts. Browsers solve this problem in two different ways. Some browsers attempt to show the content to the user as soon as possible by applying a fallback font while web fonts are loading. This will result in users seeing the text in a fallback font for a (hopefully brief) moment of time before it is replaced by the web font. This is usually referred to as the Flash Of Unstyled Text (FOUT).

IE8

IE9

IE10

IE11

Chrome

Font loading

FOUT

FOUT

FOUT

FOUT

FOIT

Timeout

n/a

n/a

n/a

n/a

3 sec.

Firefox

Safari

Safari (iOS)

Opera

Android WebKit

Font loading

FOIT

FOIT

FOIT

FOIT

FOIT

Timeout

3 sec.

3 sec.

Font loading behavior in browsers. Internet Explorer uses FOUT while others use FOIT with an optional timeout.

However, most browsers assume the FOUT is undesirable and hide any text for which web fonts are downloading. When the font has finished loading, the text will be rendered using the web font. This is referred to as the Flash Of Invisible Text (FOIT). This is especially noticeable when a paragraph combines web fonts and locally installed fonts. The sections of the paragraph that use the locally installed font will render, but the sections that use the web font will be invisible until the web font loads.

A common sight with browsers that use the flash of invisible text: content that uses web fonts are hidden while the rest of the content is visible
A common sight with browsers that use the flash of invisible text: content that uses web fonts is hidden while the rest of the content is visible.

The FOIT is usually accompanied by a timeout that, when triggered, renders the text in the fallback font. In recent versions of Chrome, Opera and Firefox this timeout is set to three seconds. The three-second timeout is based on research by both Mozilla and Google which has shown that most fonts load within three seconds7. If the web font loads after three seconds, the text will be rerendered using the web font. This means that users with slow downloading fonts (for whatever reason) first get a FOIT, followed by the FOUT, and then finally the web font. Safari and older Android browsers have no timeout, so they will not render text while web fonts are still loading (for as long that takes).

The flash of unstyled text (top) shows the content immediately and swaps out the fallback font once the web font has loaded. The flash of invisible text (bottom) hides the content while the web font is loading (possibly with a timeout)
The flash of unstyled text (top) shows the content immediately and swaps out the fallback font once the web font has loaded. The flash of invisible text (bottom) hides the content while the web font is loading (possibly with a timeout).

No matter which approach you prefer, we need a better vocabulary to discuss, control and implement custom font loading behavior. It is confusing to talk about a combination of FOUT, FOIT, FOUT followed by FOIT and timeouts that may or may not happen. This is where the proposed font-rendering property8 comes to our rescue. It introduces a vocabulary to talk about font loading behavior and proposes a new CSS property to customize this behavior.