Variable fonts—more accurately called “OpenType font variations”—are an extension of the OpenType specification . Variable fonts are single font files with support for additional features that can be managed using CSS. You can, for example, control the width of each glyph or the degree of tilt used for oblique text. If the font file supports it, you can even adjust the width of serifs, as with the Foreday font by DSType Foundry.
With variable fonts, a single font file behaves like multiple font faces. Variable fonts make the previous section of this chapter moot.
Below is pictured the letter A, from the open-source variable font Jost , in varying weights.
To use variable fonts in your project, you’ll first need a font file that supports variable font features. Axis-Praxis (pictured below) and v-fonts are two sources for discovering and experimenting with variable fonts.
Both sites include specimens and controls to play with the variable features that each font supports. Most hosted font services have small but growing selections.
Although most major browsers have implemented support for variable fonts, the number of such fonts is still fairly small in comparison to the number of traditional fonts.
1. Incorporating Variable Fonts
To incorporate a variable font, we’ll need to add another source and format hint to our CSS:
@font-face {
font-family: ‘FontFamilyName’;
src: url(‘FontFamilyName-Variable.woff2’) format(‘woff2-variations’),
url(‘FontFamilyName.woff2’) format(‘woff2’),
url(‘FontFamilyName.woff’) format(‘woff’);
}
If the browser supports variable fonts, it will download FontFamiLyName-variabLe.woff2 . If it doesn’t, it will download a file that it’s capable of parsing. This syntax above works today in every browser that supports variable fonts.
In April 2018, the CSS Working Group decided to change the syntax of format hints. As Richard Rutter explains in his article “Upcoming changes to the CSS you need for variable fonts”11:
the list of potential format strings is growing fast and could in future contain other kinds of font features, such as colour fonts. With an eye on the future, the CSS Working Group recently resolved to change the syntax of the format () hint [to] separate out the font features from the file type.
Format hints will soon use a format(‘format_name’j supports feature_name) syntax, which is shown below:
@font-face {
font-family: ‘FontFamilyName’;
/* New CSS syntax. Not yet widely implemented. */
src: url(‘FontFamilyName-Variable.woff2’) format(‘woff2’ supports variations);
}
A future-proof @font-face declaration with support for variable fonts might look like this:
@font-face {
font-family: ‘FontFamilyName’;
src: url(‘FontFamilyName-Variable.woff2’) format(‘woff2-variations’),
url(‘FontFamilyName.woff2’) format(‘woff2’),
url(‘FontFamilyName.woff’) format(‘woff’);
/* New CSS syntax. Not yet widely implemented. */
src: url(‘FontFamilyName-Variable.woff2’) format(‘woff2’ supports variations);
}
Why two src declarations? Remember: browsers ignore CSS rules they can’t understand, and the last rule wins. Adding the format(‘woff2’ supports variations) hint to our existing src declaration would cause browsers to ignore the entire rule. By using two src declarations, we guarantee that the browser will use one of them. The first src declaration will be used by browsers that don’t support the newer format hint syntax. Browsers that do support it will override the first declaration with the second.
2. Specifying Font Weight When Using Variable Fonts
As mentioned in the previous section, the font-weight descriptor lets us tell the browser which font-face file should be matched to a particular weight. Variable fonts, however, can support a range of font weights within a single file.
Instead of using a src declaration for each font-face weight, CSS4 has modified the behavior of the font-weight descriptor to accept a value range:
@font-face {
font-family: ‘FontFamilyName’;
src: url(‘FontFamilyName-Variable.woff2’) format(‘woff2-variations’),
src: url(‘FontFamilyName-Variable.woff2’) format(‘woff2’ supports variations);
font-weight: 1 1000; /* Use this file for values within this font range. */
}
Adding a font-weight range instructs the browser to use the same file for every font- weight value that falls within the range. This includes font-weight: bold , which is the equivalent of font-weight: 700 , and font-weight: normal , which is the equivalent of font- weight: 400 .
Historically, font-weight accepted numeric weight values ranging from 100-900, in increments of 100. As of CSS4—and with the advent of variable fonts—we no longer have those restrictions. For example, font-weight: 227 is now a valid, supported font-weight value. Any number greater than or equal to 1 and less than or equal to 1000 is a valid font- weight value. Fractional weights, such as font-weight: 200.5 are also valid.
3. Lower-level Font Control with font-variation-settings
CSS4 has also introduced a font-variation-settings property for finer-grained control of font features. It lets us manipulate fonts along one of five axes, using one of the registered axis tags defined in the OpenType specification.
We could, for example, use wght and itaL to set the weight and amount of italicization of an h1 selector:
h1 {
font-variation-settings: “wght” 900, “ital” .9;
}
Keep in mind that not all variable fonts support all of these axis tags. Some fonts, such as Amstelvar, support additional settings such as ytse , which controls serif height. On the left of the image below is the Latin letter A with the default serifs. On the right is the same letter with “ytse” 48 as part of its font-variation-settings declaration.
Which values we can modify, and the boundaries of those values, depends on the font file itself. You’ll need to consult the documentation for each font, if available. Because of this hurdle, your best bet is to use the font-weight , font-style , font-optical-sizing and font-stretch properties.
Source: Brown Tiffany B (2021), CSS , SitePoint; 3rd edition.