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
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.
Recommended values
- font-weight range: 100–900 (if supported by the font)
- Animate wght axis: transition: font-variation-settings 0.3s ease
- Optical sizing: font-optical-sizing: auto (enable on body)
- Use font-weight shorthand for wght axis (cleaner than font-variation-settings)
- Subset to Latin + used weights to minimize file size
- Fallback: always list static font weights as fallback in font-face stack
Common mistakes
- Declaring `font-weight: 400` in @font-face instead of `font-weight: 100 900` — the browser then only serves the font for weight 400, ignoring the rest of the axis range.
- Animating font-variation-settings without will-change: font-variation-settings — can cause layout thrashing on large text blocks.
- Picking a variable font solely for the gimmick without checking if the weight and style variations are actually distinct enough to be useful.
- Not testing fallback rendering — variable fonts require a WOFF2 fallback chain for older browsers or font-load failures.
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.