Variable fonts for web developers

Posted . Visible to the public.

This card is mainly an explanation how variable fonts work in CSS, not necessarily a recommendation to actually use them.

What is a variable font?

Designing and rendering fonts are two highly complex topics. For an arbitrary text to appear properly on your screen, its font must be created multiple times for different "settings" like stroke width (boldness) and style (e.g. italic).

Now as web developers, we usually ship these variants of the same font via multiple @font-faces of the same font-family:

@font-face
  font-family: 'My font'
  src: font-url('my_font_normal.eot')
  font-weight: normal

@font-face
  font-family: 'My font'
  src: font-url('my_font_bold.eot')
  font-weight: bold

This is battle-tested and works as intended on every browser, but has some downsides:

  • The designer has to create and update multiple font files
  • The client (browser) has to fetch the font files with multiple requests
  • You (as a developer) need to curate the mapping of font variants to their properties (e.g. font-weight)

Variable fonts try to simplify this process. They allow the designer to "pack" multiple fonts in a single file with definitions for the various appearances on different axes like font width and weight.

Before adding a variable font to your project, please be aware of those restrictions:

How to embed a variable font

Lets assume you have are given a variable font with two variants: normal (default) and bold (wght: 700). To render your page body with the given font and <strong> elements in the bold variant, your code should look similar to this example:

@font-face
  font-family: 'My variable font'
  src: font-url('my_variable_font.eot')
  font-weight: normal
  font-style: normal
  font-stretch: normal

body
  font-family: 'My variable font', Verdana, 'Helvetica Neue', Helvetica, sans-serif
  font-feature-settings: "kern" 1 ,"liga" 1, "calt" 1, "locl" 1

strong
  font-variation-settings: "wght" 700
  font-weight: normal // Ensure that the text is not fattened twice
  -moz-osx-font-smoothing: grayscale
  -webkit-font-smoothing: antialiased
  body.-no-variable-fonts &
    font-weight: 700 // Fallback for unsupported browsers

An explanation for various quirks is given below.

Pitfalls and workarounds

Always enable font smoothing

Firefox on OSX will render your text very bold if you don't enable font smoothing for variable fonts. The bast workaround is to enable font smoothing whenever you apply the "wght" font variation setting. For example, to style the <strong> element:

strong
  font-variation-settings: "wght" 700
  -moz-osx-font-smoothing: grayscale
  -webkit-font-smoothing: antialiased

Don't mix font styles with font variation settings

If a browser does not know how to render a specific font setting, it will typically result in a "graceful degradation": The browser will try to display the rendered text as good (or bad) as it can. As a result, the rendered page will look different on each browser.

Because of this, you must not set attributes like "font-weight" for variable fonts:

font-weight: bold // This setting will silently overwrite the "wght" below
font-variation-settings: "wght" 700

The code above basically disables the cool stuff. As there is no second @font-face for the same font in bold, it goes back to "your browser infers the font style however he wants. Only ever user font-variation-settings if you use a variable font!

As each browser comes with a set of default styles, I'd advise you to reset font-weight on elements like <strong>, <b> or <h1>:.

strong
  font-variation-settings: "wdth" 100, "wght" 700
  font-weight: normal // Ensure that the text is not fattened twice

Fall back to normal font styles on unsupported browsers

Firefox on Windows requires a special flag Show archive.org snapshot (layout.css.font-variations) to be enabled to properly render font variations. It seems to be enabled by default on many, but by far not all devices.

To add full support of all Browsers, you need to fall back to "font-weight: bold" (and similar variations) in this case.

if('fontVariationSettings' in document.body.style){
  document.body.classList.add('-no-variable-fonts');
}
strong
  font-variation-settings: "wdth" 110, "wght" 700
  body.-no-variable-fonts &
    font-weight: 700 // Fallback for unsupported browsers

Examples

Michael Leimstädtner
Last edit
Tobias Kraze
License
Source code in this card is licensed under the MIT License.
Posted by Michael Leimstädtner to makandra dev (2020-11-25 11:35)