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-face
s 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:
- Older browsers like IE, legacy Edge or Chrome < 61 do not support variable fonts Show archive.org snapshot
- There are various caveats and pitfalls as seen further on in this card.
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