typographyintermediate

Variable Font

An OpenType font format that encodes multiple design axes — weight, width, slant, optical size — in a single file, enabling smooth font animation and fine-grained typographic control.

Plain English

Traditional fonts are static snapshots: Regular, Bold, Italic — each a separate file. Variable fonts are the whole spectrum in one file. You can dial in exactly weight 423, or animate smoothly from thin to black as the user scrolls. This means a single font file replaces 6–8 static files, reducing page weight, and unlocks typographic effects that were impossible before — like headings that get progressively bolder as they grow in size, or text that responds to cursor position. Most major contemporary typefaces (Inter, Recursive, Fraunces, Roboto Flex) are available as variable fonts, and all modern browsers support them fully.

Technical

Declare with `@font-face { src: url("font.woff2") format("woff2-variations"); font-weight: 100 900; }` — the range tells the browser the full axis span. Control via `font-variation-settings`: `font-variation-settings: "wght" 650, "wdth" 85, "slnt" -10`. Registered axes use four-letter tags: `wght` (weight), `wdth` (width), `slnt` (slant), `ital` (italic), `opsz` (optical size). Custom axes are uppercase: `"CRSV"`, `"MONO"`. CSS shorthand `font-weight: 650` works for the `wght` axis without needing `font-variation-settings`. Animate with CSS transitions or @keyframes targeting `font-variation-settings` — browsers interpolate smoothly between values. For optical sizing, set `font-optical-sizing: auto` and pair with `font-size`. Performance: a variable font WOFF2 is typically 40–60% smaller than the equivalent set of static files for 4+ weights. Always subset to include only needed characters using tools like `pyftsubset` or Fontaine.

Live Demo

Variable Font

A single font file with continuous axes for weight, width, and more. Drag both sliders to explore the design space.

Variable fonts

400
100 Thin400 Regular900 Black
100%
75% Condensed100% Normal125% Expanded

font-variation-settings: 'wght' 400, 'wdth' 100;

One variable font file replaces a whole family — faster loads, infinite stylistic range.

Usage

✓ Good usage

A hero headline that animates from font-weight 300 to 800 on page load over 0.6s, using a single Inter variable font file — what once required two separate font files and a class swap is now one smooth CSS transition.

✗ Bad usage

Loading both a variable font AND all its static weight variants as separate font files — the variable font is meant to replace the static files, not supplement them, doubling the download instead of halving it.

Common mistakes

AI Prompt Example

Copy this into Claude, Cursor, Bolt, or v0.

Switch the heading font to Inter Variable. In @font-face, declare `font-weight: 100 900` and `font-style: normal`. Set `font-optical-sizing: auto` on the root. For the hero h1, animate from `font-weight: 200` to `font-weight: 800` on load using a CSS @keyframes transition over 0.5s ease-out. Replace all separate font-weight @font-face declarations with this single variable font file.