Variable Fonts: One File, Every Weight
A typeface family used to mean a stack of separate files: Regular, Medium, Bold, Bold Italic, and so on, each one a fixed, finished design. A variable font collapses that whole stack into a single file that can produce any weight, width, or slant in between, calculated on the fly. This article covers how that works, what you can actually control from CSS, and includes a live slider so you can feel the difference rather than just read about it.
Variable fonts, in one screen
A variable font stores a range along one or more "axes," rather than a single fixed design, and lets the browser pick any point along that range.
A static font stores one fixed outline per glyph. A variable font instead stores a small number of extreme "master" outlines for each glyph, a Thin master and a Black master, say, plus instructions for how to interpolate smoothly between them. When a browser needs a weight in between, like 550, it doesn't pick a pre-made design; it calculates one on demand by blending the masters, and it can do that for any value the axis allows, not just round numbers.
This is still delivered as one ordinary font file, usually .woff2 on the web, just one that's typically larger than a single static weight, because it's carrying the master outlines and interpolation data for the entire range. In exchange, it's almost always smaller than shipping several static weights separately, and it offers values no static release ever did: the exact weight that looks right at a specific size, rather than whichever pre-cut weight happens to be closest.
This is the whole idea of variable fonts in one control. The text below is one single font file (Inter, requested from Google Fonts as a variable range) rendering every value the slider passes it, not switching between a handful of pre-made weights.
OpenType formally registers five axis tags, each with a standardized meaning and its own CSS property. A font can implement any subset of these (nothing requires all five), and most variable fonts released today implement only wght, sometimes paired with wdth or opsz.
Beyond the five registered axes, a type designer can define entirely custom ones: a grade axis that shifts weight slightly without changing the letter widths (useful for matching perceived weight across light and dark backgrounds), or axes that control things as specific as counter size or serif length. Custom axes use uppercase four-letter tags to distinguish them from the lowercase registered ones, and, just like the stylistic sets covered in the OpenType Feature Reference, there's no universal meaning to a custom tag across different fonts. You have to check the specific font's own documentation for what it does.
Because no CSS shorthand exists for an arbitrary axis, custom axes are only reachable through font-variation-settings, using the exact tag the font defines, for example, font-variation-settings: "GRAD" 30; for a font that ships a grade axis.
A variable font's axis is continuous, but most type designers still want to recommend a handful of specific points along it, the coordinates that correspond to what would have been "SemiBold" or "Condensed Bold" in a static release. These are called named instances, and they're stored right in the font's fvar table alongside the axes themselves. Design and office software can list them as a familiar style menu, and CSS's own font-weight keywords (like bold) map onto the nearest matching instance automatically. None of this limits what the axis can actually do. The values between named instances are still fully available to anyone who reaches for them directly.
Exactly like the OpenType feature properties covered elsewhere in this series, the five registered axes each have a familiar CSS shorthand, while anything else, including custom axes, needs the raw syntax.
Shorthand properties
- font-weight: 550;
- font-stretch: 85%;
- font-style: italic;
- font-style: oblique 12deg;
- font-optical-sizing: auto;
Raw axis tags
- font-variation-settings: "wght" 550;
- font-variation-settings: "wdth" 85;
- font-variation-settings: "opsz" 36;
- font-variation-settings: "GRAD" 30; (custom)
- Multiple axes: comma-separate the pairs
One rule worth remembering: wherever font-variation-settings and a shorthand property both target the same axis, the raw setting wins, regardless of the order they're written in. Mixing the two for the same axis rarely does what you'd expect, so pick one approach per axis.
Beyond the obvious performance win of shipping one file instead of six, variable fonts open up a few things static fonts simply can't do. Because font-weight and font-variation-settings are ordinary, animatable CSS values, many browsers can smoothly transition or animate a variable axis with plain CSS: a heading that gently gains weight on hover, without a single extra image or font file. And because the weight or width can be tied to something like viewport size, type can respond fluidly to its container the same way layout already does, instead of jumping between a small, fixed set of pre-cut styles.