Variable fonts on the web: how they work and when one file beats several
A variable font is a single font file that contains a continuous range of styles, such as every weight from light to black, instead of one file per style. For a site that uses three or more weights or widths of a family, one variable file is usually smaller and more flexible. For a site that uses one or two weights, static files can still be lighter.
What variable fonts are
Variable fonts arrived with OpenType font variations, part of OpenType 1.8, announced in 2016 as a joint effort by Adobe, Apple, Google and Microsoft. Instead of storing each weight as a separate font, the file stores a set of outlines plus instructions for how each point moves along one or more axes. The browser can then render any value along those axes: weight 400, 450 or 437 are all available from the same file. MDN's variable fonts guide covers the format and browser support, which now includes every current major browser.
The axes worth knowing
| Axis tag | Controls | CSS property | Worth using for |
|---|---|---|---|
| wght | Weight, thin to black | font-weight | Nearly everything: a heading weight between bold and black, a lighter body weight on dark backgrounds |
| wdth | Width, condensed to expanded | font-stretch | Long headlines in narrow columns, condensed display type |
| opsz | Optical size | font-optical-sizing | Fine detail at small sizes and refined shapes at display sizes |
| ital | Italic on or off | font-style: italic | Families that put italics in the same file |
| slnt | Slant angle | font-style: oblique | Sans-serifs with an oblique rather than a true italic |
Fonts can also have custom axes, written in capital letters, such as a grade axis (GRAD) that changes weight without changing width, useful for adjusting text on dark backgrounds without reflowing the layout. Custom axes are set with the lower-level font-variation-settings property.
Variable font CSS
- Declare the range in
@font-face. For a self-hosted file, writefont-weight: 100 900;(andfont-stretch: 75% 125%;for a width axis) so the browser knows which values the file covers. - Use the standard properties first.
font-weight: 650andfont-stretch: 80%work with variable fonts and fall back sensibly. Reservefont-variation-settingsfor custom axes, because it overrides the standard properties and doesn't inherit in a friendly way: setting one axis on a child resets the others. - Leave optical sizing on. Browsers apply the opsz axis automatically when a font has it (
font-optical-sizing: auto). - Load with
font-display: swapso text shows in a fallback font while the variable file downloads. - Subset where you can. A variable file with many axes and full language coverage can be large; request only the axes, ranges and character sets you use.
Google Fonts serves variable families through its CSS API with a range syntax: family=Inter+Tight:wght@300..800 requests the weight axis from 300 to 800, and family=Archivo:wdth,wght@62..125,400..900 adds a width axis. Requesting a narrower range produces a smaller file.
Variable fonts performance: when one file wins
A variable file is larger than any single static weight, because it carries the variation data. It wins once a page would otherwise load several static files: one request instead of three or four, and every in-between weight available for free. If your site uses only regular and bold, two well-subsetted static files may be smaller in total. Check the real transfer sizes in your browser's network panel rather than assuming.
- Good fit: a single family doing headlines, body and labels at several weights, condensed headlines plus normal-width body, or responsive type that changes weight or width with screen size.
- Poor fit: a site using one weight, or a family whose variable version covers far more axes or languages than you need and can't be subset.
- Avoid: animating weight or width on scroll or hover across large blocks of text. It reflows the layout on every frame, and moving text is hard to read.
Variable fonts in Anticode
Each of Anticode's seven design systems uses one family from Google Fonts and requests it as a weight range rather than separate weights: Editorial's Geist at 300 to 700, Technical's IBM Plex Sans at 300 to 700, Luxury's Jost at 300 to 700, Playful's Fredoka at 300 to 700, Organic's Figtree at 300 to 800, Swiss's Inter Tight at 300 to 800, and Brutalist's Archivo at 400 to 900. Archivo is the one that also brings a width axis, from 62 to 125, and the Brutalist system uses it: hero headlines and section headings are set at 75% width (font-stretch: 75%) at weight 900.
Because a whole site uses one family, one file covers headings, body and labels. The Critic checks for a single family and flags the handful of fonts nearly every AI-built site picks; see how to choose a website font for picking type more generally.
Questions people ask
What are variable fonts?
Single font files that contain a continuous range of styles along axes such as weight and width, rather than one file per style.
Are variable fonts smaller than static fonts?
Smaller than several static files together, larger than one. They pay off when a site uses three or more weights or widths.
Should I use font-variation-settings or font-weight?
Use font-weight, font-stretch and font-style for registered axes. Keep font-variation-settings for custom axes, since it overrides the others.
Sources
- Variable fonts guide, MDN Web Docs, checked
- CSS API update (CSS2), Google Fonts, checked