CSS Variable Fonts: How to Use Flexible Font Axes
Variable fonts let one font file behave like many fonts by exposing adjustable axes such as weight, width, slant, and optical size. In CSS, that means you can fine-tune typography with fewer files, smoother transitions, and more precise control over text styling.
Quick answer: A variable font is a single font file with one or more adjustable axes. In CSS, you usually control it with font-weight, font-stretch, font-style, and sometimes font-variation-settings.
Difficulty: Intermediate
You'll understand this better if you know: basic CSS syntax, how @font-face works, and the difference between font families and font properties.
1. What Are CSS Variable Fonts?
CSS variable fonts are fonts built on OpenType variable font technology. Instead of shipping separate files for regular, bold, condensed, or italic styles, a single file can include a continuous range of design variations.
- One file can represent many font instances.
- Axes can be built into the font by the type designer.
- CSS can request values along those axes instead of only fixed named styles.
- They work especially well for responsive and animated typography.
Traditional fonts often expose only a few static files, such as Regular, Bold, and Italic. Variable fonts can interpolate between those extremes and often beyond them.
2. Why Variable Fonts Matter
Variable fonts matter because they reduce file count while giving designers and developers more control. That can improve performance, simplify asset management, and create typography that adapts more smoothly to layout changes.
They are especially useful when a site needs multiple weights or widths across headings, body text, and responsive breakpoints. Instead of loading many separate font files, you may only need one or two variable files.
They are not always the best choice for every project, though. If a site only needs one static face and one bold face, a small set of traditional files may still be simpler.
3. Basic Syntax or Core Idea
The core idea is that you load a variable font with @font-face and then set the font family in normal CSS. If the font supports standard CSS properties for its axes, use those first.
Loading a variable font
This example defines a font family that points to a variable font file. Notice the font-weight range, which tells the browser the font can handle more than one weight value.
@font-face {
font-family: "InterVariable";
src: url("/fonts/InterVariable.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
}That rule tells the browser the file can serve a range of weights. Once the family is available, you can apply it like any other font family.
Using the font on text
body {
font-family: "InterVariable", sans-serif;
font-weight: 450;
}This works because the browser maps the requested weight to the closest point supported by the variable font.
Directly setting an axis
When you need access to a custom axis or finer control, use font-variation-settings. This is the lower-level interface for variable font axes.
h1 {
font-family: "InterVariable", sans-serif;
font-variation-settings: "wght" 750, "wdth" 90;
}Here, wght controls weight and wdth controls width, if the font includes those axes.
4. Step-by-Step Examples
Example 1: Regular body text and bold headings
A common use case is a single variable font that handles the whole page. The browser can render body text with a lighter weight and headings with a heavier one without switching font files.
body {
font-family: "Source Sans Variable", sans-serif;
font-weight: 400;
}
h1,
h2 {
font-family: "Source Sans Variable", sans-serif;
font-weight: 700;
}This shows the simplest benefit of variable fonts: consistent typography from one family with a continuous weight range.
Example 2: Responsive width changes
Some variable fonts support a width axis. That allows you to make text feel wider on large screens and more compact on smaller screens.
.headline {
font-family: "Roboto Flex", sans-serif;
font-variation-settings: "wght" 650, "wdth" 100;
}
@media (min-width: 900px) {
.headline {
font-variation-settings: "wght" 650, "wdth" 85;
}
}The text becomes visually narrower on larger screens, which can help fit longer headlines into tighter layouts.
Example 3: Optical size for better readability
Some fonts expose an optical size axis, often written as opsz. Smaller text can use a version designed for readability, while larger headings can use a style optimized for display.
article {
font-family: "Source Serif Variable", serif;
font-variation-settings: "opsz" 14;
}
article h2 {
font-variation-settings: "opsz" 36;
}This is useful when the font is designed to look different at text sizes versus display sizes.
Example 4: Slant instead of separate italic files
Some variable fonts provide a slant or italic-related axis. That can reduce the need for separate italic files, though the exact behavior depends on the font design.
.quote {
font-family: "Recursive", sans-serif;
font-variation-settings: "slnt" -10;
}That example leans the glyphs using a built-in slant axis instead of switching to a separate italic face.
5. Practical Use Cases
- Design systems that need many heading and body text weights without many font files.
- Responsive websites that adjust text width or weight at different breakpoints.
- Editorial layouts that need strong typographic hierarchy with subtle variation.
- Brand sites that want animated or expressive typography while keeping file counts lower.
- Interfaces where consistency across many text styles matters more than using multiple unrelated fonts.
6. Common Mistakes
Mistake 1: Using font-variation-settings for everything
Many developers jump straight to the low-level axis syntax even for common weight changes. That works, but it is harder to read and can override more accessible CSS font properties.
Problem: Using font-variation-settings for standard axes can make your CSS harder to maintain and can conflict with font-weight, font-style, or font-stretch.
p {
font-family: "InterVariable", sans-serif;
font-variation-settings: "wght" 400;
}Fix: Use font-weight for the weight axis when possible, and reserve font-variation-settings for custom or unsupported axes.
p {
font-family: "InterVariable", sans-serif;
font-weight: 400;
}The corrected version is easier to understand and lets the browser apply the font in the most natural way.
Mistake 2: Forgetting to declare the supported range in @font-face
If the browser does not know the font supports a weight range, it may treat the font like a single static face. Then requests for bold or light styles may not behave as expected.
Problem: Without a range declaration, the browser may not map weight values correctly, so the variable font appears to ignore your font-weight changes.
@font-face {
font-family: "InterVariable";
src: url("/fonts/InterVariable.woff2") format("woff2");
}
h1 {
font-family: "InterVariable", sans-serif;
font-weight: 800;
}Fix: Declare the axis range that the font supports.
@font-face {
font-family: "InterVariable";
src: url("/fonts/InterVariable.woff2") format("woff2");
font-weight: 100 900;
}Once the browser knows the range, it can choose the correct point on the axis.
Mistake 3: Assuming every variable font supports every axis
Not all variable fonts expose the same axes. A font may support weight but not width, or optical size but not slant.
Problem: If you set an axis the font does not include, the property may have no visible effect, which often looks like the font is broken.
.logo {
font-family: "SomeFontVariable", sans-serif;
font-variation-settings: "wdth" 75;
}Fix: Check the font documentation or use only axes you know the font provides.
.logo {
font-family: "SomeFontVariable", sans-serif;
font-weight: 700;
}The corrected version uses a supported axis, so the browser can render a visible change.
7. Best Practices
Use standard CSS properties first
When a variable font supports a common axis like weight or width, prefer the matching CSS property. This improves readability and keeps your code aligned with the browser’s typography model.
h2 {
font-family: "InterVariable", sans-serif;
font-weight: 650;
}That is clearer than hiding the same idea inside low-level axis settings.
Declare axis ranges in @font-face
Explicit ranges help browsers understand what the font can do. They also make your font loading rules easier to debug later.
@font-face {
font-family: "Acme Variable";
src: url("/fonts/acme-variable.woff2") format("woff2");
font-weight: 300 800;
font-stretch: 75% 125%;
}This gives the browser enough information to map requested values cleanly.
Test across sizes, not just weights
A variable font can look very different at small body text sizes versus large display sizes. Optical sizing, width changes, and heavier weights can all affect spacing and readability.
small {
font-family: "Source Serif Variable", serif;
font-size: 0.875rem;
}
h1 {
font-family: "Source Serif Variable", serif;
font-size: 3rem;
}The same font can need different tuning at different sizes, so test typographic scales rather than single samples.
8. Limitations and Edge Cases
- Not every font is variable. If the font file does not expose variation axes, the CSS properties will not create them.
- Browser support is good in modern browsers, but older browsers may fall back to static font files or ignore some variation behavior.
- Some axes are custom and can only be controlled with font-variation-settings.
- Accessible and semantic CSS properties such as font-weight are usually better than low-level axis names for common styling.
- Very large file sizes are still possible if the font family contains a wide character set or many design axes.
- Some fonts make a visible jump at the extremes of their range, so continuous control does not always mean perfectly smooth visuals.
If a variable font seems not to work, the first things to check are the font file format, the declared axis range, and whether the browser actually supports the axis you are trying to use.
9. Practical Mini Project
Let’s build a small card layout that uses one variable font for both body text and headings. The goal is to use different weights and sizes while keeping the typography consistent.
@font-face {
font-family: "Avenir Next Variable";
src: url("/fonts/avenir-next-variable.woff2") format("woff2");
font-weight: 300 800;
}
.card {
font-family: "Avenir Next Variable", sans-serif;
font-weight: 400;
line-height: 1.5;
padding: 1.5rem;
border: 1px solid #ddd;
border-radius: 0.75rem;
}
.card h2 {
font-weight: 750;
margin-top: 0;
}
.card p {
font-weight: 350;
}This mini project shows how one variable font can supply a light paragraph style and a heavier heading style without changing the font family.
10. Key Points
- Variable fonts use one file to provide many font variations.
- Standard CSS properties are the easiest way to control common axes like weight and stretch.
- font-variation-settings is useful for custom or advanced axes.
- Declare axis ranges in @font-face so the browser can map values correctly.
- Always test typography at different sizes, not just one sample screen.
11. Practice Exercise
- Load a variable font family using @font-face.
- Apply one weight to body text and a heavier weight to headings.
- Try one custom axis, such as width or slant, if the font provides it.
- Verify that the font still looks readable at small and large text sizes.
Expected output: A simple page where body text, headings, and one highlighted element all use the same variable font with visibly different axis values.
Hint: Start with font-weight, then add font-variation-settings only if the font documentation lists an extra axis.
Solution:
@font-face {
font-family: "Practice Variable";
src: url("/fonts/practice-variable.woff2") format("woff2");
font-weight: 200 800;
}
body {
font-family: "Practice Variable", sans-serif;
font-weight: 350;
}
h1 {
font-weight: 750;
}
.label {
font-variation-settings: "wdth" 85;
}12. Final Summary
CSS variable fonts give you a flexible way to control typography with fewer font files and more granular design choices. They are especially valuable when your layout needs multiple weights, widths, or optical sizes and you want those changes to feel smooth and consistent.
In most cases, start with standard CSS typography properties such as font-weight and font-stretch. Use font-variation-settings only when you need a custom axis or more direct control. That balance keeps your CSS easier to maintain while still taking advantage of what variable fonts can do.
If you are building a design system or a content-heavy site, the next step is to inspect a real variable font’s axis list and experiment with how it behaves at different sizes and weights.