How to Implement Variable Fonts on the Web
Tags: variablefonts, typography, webdesign
Published: 2019-02-01 18:55:30

---
title: How to Implement Variable Fonts on the Web
published: true
description: This article aims to discuss what to consider when implementing variable fonts on the web, as well as how to add variable fonts to a website.
tags: variable fonts, typography, web design
---
This article aims to discuss what to consider when implementing variable fonts on the web, as well as how to add variable fonts to a website.

Variable fonts are at the time of writing supported in most major browsers, and available for [approximately 78% of all users](https://caniuse.com/#feat=variable-fonts). Hence, there are no excuses for not taking advantage of the technology.

If you need a quick refresh on the subject, have a look at our blog post [“Variable Fonts on the Web”](https://redonion.se/en/variable-fonts-on-the-web/) for an overview of variable fonts.

<hr>

##Performance
**_Subsetting_**
Variable font files tend to get rather large since they are containing a lot of data for different font variations. The most common practice seems to be subsetting the font if that is feasible. A word of warning though, it seems that a lot of the tools used for creating font subsets also sometimes removes data that is needed to keep the variable parts of the font data.

The tool [Glyphhanger](https://www.npmjs.com/package/glyphhanger) is said not to remove any unnecessary data when subsetting variable fonts. [Fonttools](https://github.com/fonttools/fonttools) is another alternative.

**_woff2_**
Converting the file to woff2 format is also a way of trying to keep it as light-weight as possible. One of many tools for the job is a command line tool by Google called [woff2](https://github.com/google/woff2).

**_@supports_**
Modern browsers only download a font when it is needed – that is when it is used in a CSS selector that matches a node connected to the DOM. That means it is possible to use `@supports` to only download the font in supporting browsers.

<hr>

##Axes
These are the default or “registred” axes. Just remember that not all fonts will use all axes. Even if an axis is defined, the values defined within the font might only be part of the span of possible values.

**wght** corresponding to `font-weight`. Value is anything between 1 to 999. Can also use keywords:

* thin or hairline (100)
* extra light or ultra light (200)
* light (300)
* normal (400)
* medium (500)
* semi bold or demi bold (600)
* bold (700)
* extra bold or ultra bold (800)
* black or heavy (900)
* inherit / initial / unset

**wdth** corresponding to `font-stretch`. Value is anything between 50% to 200%. Can also use the keywords:

* ultra-condensed (50%)
* extra-condensed (62.5%)
* condensed (75%)
* semi-condensed (87.5%)
* normal (100%)
* semi-expanded (112.5%)
* expanded (125%)
* extra-expanded (150%)
* ultra-expanded (200%)
* inherit / initial / unset

**ital** corresponding to `font-style: italic`. Value is from oblique -90deg to oblique 90deg.

**slnt** corresponding to `font-style: oblique`. Values between -90deg and 90deg with a default to 14deg.

**opsz** corresponding to `font-optical-sizing`. Set to auto or none. The initial value is auto, which means it is active by default if the axis exists on the variable font in use.

**_Italic vs. Oblique_**
The difference between an italic and an oblique font is that the italic version of a font is both angled and has a slightly tweaked glyph design. The oblique version is angled and adjusted as such, but otherwise, there is no difference to the roman (normal and upright) version of the font.

**_Font-optical-sizing_**
Font-optical-sizing is size-specific optimizations to improve a font’s readability. It is used to adjust the font depending on the environment where it is being used. For example, a font can be programmed to add embellishments when viewed on larger screens, to remove fine details on smaller text, or to increase x-height (the height of lower case letters, aligned with the height of the letter “x”) in certain situations to improve readability.

Variable fonts with this axis implemented, therefore, makes websites more accessible.

**_Custom Axes_**
Font designers can create custom axes, giving them a name consisting of any 4 letters. Custom axes are used to control any other aspect of a font that the designer wishes to be able to gradually alter.

<hr>

##Adding a Variable Font to a Web Page
Adding a variable font to a web page is done with @font-face. The file format is set to the file type. In previous implementations, a suffix “-variations” was used, but now it does [not seem to be needed](https://www.w3.org/TR/css-fonts-4/#font-face-src-formats).

```css
@font-face{
    font-family: "variableFont";
    src: url("variableFont.woff2") format("woff2");
}
```

**_Font-variation-settings_**
To control the axes and set font variations, it is possible to use either the CSS property `font-variation-settings`, or the properties `font-weight`, `font-stretch`, `font-style` and `font-optical-sizing` separately.

According to the [spec](https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def), the preferred way is to use the properties for each style separately. Reason being that `font-variation-settings` is meant to be used for custom axes. If you run into browser compatibility problems, `font-variation-settings` is rumoured to be more stable across browsers.

No matter which syntax you use, you need to find out which axes are supported in the variable font, and between which values they range. Unless this is specified in any documentation that you can find about the font, this information should be found in the [font variation (fvar) tables](https://docs.microsoft.com/sv-se/typography/opentype/spec/fvar) in the font files.

The easiest way of extracting this information is to drop the font into the [wakamaifondue.com](https://wakamaifondue.com/) and hope the info you need will be revealed. If that is not the case, you might need to use a tool like [FontView](https://github.com/googlei18n/fontview) in combination with [Fonttools](https://www.npmjs.com/package/fonttools) as described more in-depth in this [article](https://webinista.com/updates/how-to-find-variable-font-axis-fonttools/).

**_Add Axis Range_**
Specify the range for the axis you wish to use. Otherwise, the property might use a default fallback that risk hindering usage of the variable font. In the future `font-weight` will, for example, get a default fallback of auto, meaning the range might not be needed.

```css
@font-face{
    font-family: "variableFont";
    src: url("variableFont.woff2") format("woff2");
    font-weight: 1 999;
}
```
**_Fallbacks_**
Add the non-variable font or fonts using `@font-face` as usual.
```css
/*Fallback fonts*/
@font-face {
    font-family: "fallbackFont";
    src: url("fallbackFont-regular.woff2") format("woff2"),
         url("fallbackFont-regular.woff") format("woff");
    font-weight: 400;
}

@font-face {
    font-family: "fallbackFont";
    src: url("fallbackFont-bold.woff2") format("woff2"),
         url("fallbackFont-bold.woff") format("woff");
    font-weight: 700;
}
```
Add the `@supports` rule. If you experience inconsistent weight behavior in different browsers, try adding the default weights you want each font to use. (Advice from [“How to use variable fonts in the real world”](http://clagnut.com/blog/2390/).)

```css
html {
    font-family: "fallbackFont", sans-serif;
    font-weight: 400; /*if inconsistent weight behavior*/
}

strong, b {
    font-weight: 700;
}

@supports (font-variation-settings: normal) {
    html {
        font-family: "variableFont", sans-serif;
        font-weight: 400;
        /*if you run into browser compatability problems,
        try the syntax:
        font-variation-settings: "wght" 400; */
    }

    strong, b {
        font-weight: 625;
    }
}
```
**_Future syntax_**
In the future, the syntax would change to make it possible to incorporate checking for browser support in the `format()` part. That would make it possible to use variable fonts outside of `@supports` rules, and still have a fallback solution in place.
```css
/*Future syntax*/
@font-face {
    font-family: "futureVariableFont";
    src: url("fallbackFont.woff2") format("woff2"),
          url("fallbackFont.woff") format("woff");
    src: url("futureVariableFont.woff2") format("woff2" supports variations);
}
```
**_Word of Advice_**
Since the specs might change and the technology is ever evolving, testing is key to make sure the font displays and behaves as expected in the browsers and browser versions most important to you.

There might still be undiscovered quirks and edge cases that need to be worked around. If you come across one of those, please share your experiences and solutions with the community. That is what makes it possible for all to keep up with the rapid changes of the web world.

<hr>

*Originally published at [redonion.se](https://redonion.se/en/how-to-implement-variable-fonts-on-the-web/).*