font optimizations

In our article Webperf: Optimizing font loading, we demonstrated the impact that font loading can have on site performance.
In particular, we noticed that the Speed Index and the Start Render fell by an average of 5 to 10% when fonts were not loaded.

When it comes to font optimization, the tool that’s generally recommended is Font-Squirrel. It’s a fantastic tool, but it does have the drawback of being manual. So we decided to retain its best features to develop our own automatic font optimization engine.
Here, we’ll cover:

  1. generating fonts in WOFF2 format
  2. automatically updating the CSS @font-face declaration
  3. adding the font-display property
  4. minifying fonts via the subsetting technique
  5. font autohinting for better visual rendering in Windows
  6. optimizing loading of Google Fonts

At the dashboard level, you can set all of the font optimization settings in the settings section:

font optimization webperf

1. Automatically generating fonts in WOFF2

WOFF2 is the most advanced font format. It offers the benefit of reducing file size by 30% on average and by over 50% in certain cases compared to the WOFF format.

The main change compared to WOFF is the switch to a brotli compression algorithm instead of gzip (or zopli). It also remembers the body of an unaccented character and reuses it when displaying an accented version (meaning it’s no longer necessary to have a new character for each accent).

WOFF2 is currently supported by all recent browsers.

WOFF 2.0 - Web Open Font Format

Essentially, the Fasterize engine is now capable of interpreting a new type of format conversion URL in the following format:
http://www.domain.com/fstrz/r/c/www.domain.com/fichier.woff.woff2

The source file path is located between /fstrz/r/c and the .woff2 extension. In the example above, the source file is http://www.domain.com/fichier.woff. This format is based on our URL rewriting mechanism, which is currently used for the unsharding feature.

This URL schema allows WOFF2 format to be generated from the following formats: TTF (truetype), OTF (opentype) and WOFF (Web Open Font Format). The EOT (embedded-opentype) format is an outdated format that is only used by old versions of the Internet Explorer browser. Fasterize does not support this format.

Even though they are less useful, Fasterize is able of generating WOFF or TTF format for browsers that do not support WOFF2. For example, the following URL is used to create a font in WOFF format from TTF format:
http://www.domain.com/fstrz/r/c/www.domain.com/fichier.ttf.woff

Among our test clients, some font files were reduced from 173 Kb (in WOFF format) to 99 Kb (WOFF2), a saving of almost 43%.

2. Automatically updating the src property of @font-face declarations

Fasterize also automatically updates the src property of @font-face declarations.

To illustrate how this property is updated, let’s consider the following @font-face declaration (which is anything but optimized):

@font-face {
	font-family: 'MyFontFamily';
	src: url('myfont-webfont.ttf') format(‘true-type’), url('myfont-webfont.svg');
}

The src property of @font-face declarations is a prioritized list of different potential file formats. The browser chooses the source of the file by examining the listed elements in order. To detect the file format, the browser takes the format entered in each source’s ‘format’ function as a starting point. This means that it’s absolutely essential to put the most compressed format first.

In our case, our engine does the following:
it adds the WOFF and WOFF2 format if they are not included in the property
it puts the sources in the right order, including the hack to support Internet Explorer 9 (#iefix)
it adds the missing format declarations in the format function (in the previous example, the truetype format).

Here is the declaration as modified by the engine:

@font-face {
  font-family: 'MyFontFamily';
  src: 
       url('http://www.domain.com/fstrz/r/c/myfont-webfont.ttf.woff2') format('woff2'),
       url('http://www.domain.com/fstrz/r/c/myfont-webfont.ttf.woff') format('woff'),
       url('myfont-webfont.ttf')  format('truetype'),
       url('myfont-webfont.svg#svgFontName') format('svg');
}

In the same way as the browser, our engine determines the format of the various sources using the following indications in priority order:

  1. the format declaration in the format function. For example, woff format.
  2. the extension in the URL.
  3. the mime-type declaration if the font is in-lined in base64.

A widespread practice used to reduce download times is to a href="http://stephenscaff.com/articles/2013/09/font-face-and-base64-data-uri/" target="_blank" rel="noopener">incorporate the font in base64 into the @font-face declaration. Let’s take the example of the following declaration:

@font-face {
  font-family: 'MyFontFamily';
  src: 
       url('data:application/x-font-woff;base64,d09GRgABAAAAAEwMAA0AAAAAjawA.....') format('woff'),
       url('myfont-webfont.ttf')  format('truetype');
}

This practice is intended to eliminate an HTTP request on the critical path and thus avoid text flash. However, in the age of HTTP/2, the preload tag and the font-display declaration, this is looked down on. It slows down CSS analysis and fills up bandwidth.

The engine isn’t going to unnecessarily insert a WOFF2 source before the inlined WOFF source as shown here:

@font-face {
  font-family: 'MyFontFamily';
  src: 
       url('http://www.domain.com/fstrz/r/c/myfont-webfont.ttf.woff2') format('woff2'),
       url('data:application/x-font-woff;base64,d09GRgABAAAAAEwMAA0AAAAAjawA.....') format('woff'),
       url('myfont-webfont.ttf')  format('truetype');
}

This would result in the same file being downloaded twice (once in WOFF2 and once in the body of the CSS file).

Instead, the engine will adopt two behaviours:

  • if it is able to retrieve the URL of the source file from a declaration in another format (for example, TTF), it will then rewrite two URLs for WOFF and WOFF2 format. In this case, the inlining of the WOFF format is not retained.
    @font-face {
      font-family: 'MyFontFamily';
      src: 
           url('http://www.domain.com/fstrz/r/c/myfont-webfont.ttf.woff2') format('woff2'),
           url('http://www.domain.com/fstrz/r/c/myfont-webfont.ttf.woff') format('woff'),
           url('myfont-webfont.ttf')  format('truetype');
    }
  • if it is not able to retrieve the URL from another format, the WOFF2 format will not be added to the sources. The declaration will remain unchanged.

3. Adding the @font-face declaration font-display property

The font-display property is a property supported by Chrome browsers and which will also appear in Firefox 58. It allows the developer to decide how fonts are applied (or not applied) based on their download time. You can read about this property in more detail here: CSS Font Rendering Controls Module Level 1.

@font-face {
  font-family: "Open Sans Regular";
  font-weight: 400;
  font-style: normal;
  src: url("fonts/OpenSans-Regular-BasicLatin.woff2") format("woff2");
  font-display: swap;
}
CSS Font Rendering Controls

Without this property, your browser adopts different behaviours while the font downloads:

  • FOUT: Flash Of Unstyled Text – where the browser displays the text in an unstyled font before displaying the correct font. This is the case for the Internet Explorer and Edge browsers.
  • FOIT: Flash Of Invisible Text – where the browser does not display the text until the font has been downloaded. This means that the text remains invisible. This is the case for the Chrome, Firefox, Safari and Opera browsers. To avoid this SPOF, Chrome, Firefox and Opera will wait a maximum of 3 seconds before displaying text.
FOUT vs FOIT

From the dashboard, you can now choose one of the possible behaviours via the font-display property:

  • auto: the font display strategy is determined by the user agent.
  • block: the text is not displayed until the font is downloaded (cf. FOIT above)
  • swap: the unstyled text will be immediately displayed and replaced with the correct font once it has been downloaded (cf. FOUT above). This is often the behaviour required by JavaScript solutions based on FontObserver.
  • fallback: this is a compromise between auto and swap. There will be a short period of time (100ms according to Google) during which the text will not be visible, then the unstyled text will be displayed. Once the font has been loaded, the text will be styled.
  • optional: works like fallback, with the text initially being invisible for a short period of time before becoming visible but not styled. However, the browser can choose not to use the font for slow connections or to only use the font if it is already cached.
font block swap fallback optional

The recommended mode, which we implement by default, is swap. This ensures the text is quickly displayed.

4. Subsetting, or font minification

Subsetting is used to reduce the number of characters contained in a file based on a given language or unicode range. In essence, it’s a form of minification designed for fonts: we eliminate all unnecessary characters.

In this example we only retain characters from the basic-latin unicode range.

range unicode

The benefit of this technique is that there is an almost one-to-one relationship between the file size and number of characters. This means that this is a very effective technique for reducing the file size.

To make your life easier, we also support subsetting by language. If your site is in English, simply choose English from the menu. However, if your site is translated into several Western European languages, we recommend using the ‘Latin’ range.

The difficulty with automated subsetting lies in the management of fonts that do not have characters in the targeted unicode range. The most common case is for icon fonts (such as Font-Awesome). Our engine detects this type of file so it doesn’t delete the characters.

On our test site, this optimization allowed us to further reduce the font file size by 79%, from 99 Kb (with WOFF2) to 21 Kb.

5. Using autohint for better rendering in Windows

Hinting is a fundamental technique in font generation. These are rendering indications included in the file that can be used to adjust the font to make it easier to read on some OSs. This helps to ensure that certain characters are rounded.
Windows requires hinting for correct font rendering, while the rendering engine used by Mac OS and Linux does not use hinting. Hinting can be adapted depending on the Windows font rendering engine (ClearType, DirectWrite).

autohint

As with the majority of font generators, such as Font-Squirrel, our engine consistently applies ttfautohint to generated fonts. This allows us to ensure that hints are included in the file.

6. Optimizing loading of Google Fonts

Fonts downloaded via Google Fonts are optimized for the browser and the OS in terms of CSS declaration and format. The WOFF2 format and the unicode-range property are therefore used as a result.
However, to accelerate rendering for these fonts, we recommend that you add a link rel=preconnect tag to your Fasterize tag manager.

ajouter une balise link rel=preconnect dans votre tag manager Fasterize

This opens a connection to fonts.gstatic.com, which is used by Google Fonts, before the CSS file is even downloaded. This saves you precious milliseconds on the critical path of rendering (the metric used for start render).

fonts.gstatic.com

Conclusions

This set of optimizations has been developed with the aim of ensuring overall consistency in terms of font loading. Each optimization works in complement to the others and once again gives you more flexibility and saves you time.
To access these optimizations, simply log in to your Fasterize Dashboard, go into your settings, and view the font loading optimization options.

And if you haven’t fasterized your website yet, you still can...!

Run a test!