Door 16 – Variable Fonts | CSS Adventskalender
Skip to content

Door 16 – Variable Fonts

Published: at 07:00 AM

Variable Fonts are one of the biggest advances in web typography since the introduction of web fonts themselves. Instead of loading separate files for each font style variant (Regular, Medium, Bold, Black …), a single font file contains all variants – controllable via axes like wght, wdth, opsz, and many more.

The result is more expressiveness, better performance, consistent typographic systems, and new design possibilities.

This door shows how Variable Fonts work, when they make sense, and how to use them optimally for modern UIs.

How Variable Fonts Work

Variable Fonts represent a fundamental paradigm shift in digital typography. While traditional fonts require a separate file for each weight (Regular, Medium, Bold, etc.), a Variable Font contains all variants in a single file. Technically speaking, Variable Fonts are OpenType fonts with so-called variation axes. These axes define continuous value ranges that can be controlled via CSS.

The technology is based on interpolation. The font designer defines two or more master designs, for example a very light and a very heavy weight. The browser then automatically calculates all intermediate values. This means: You are no longer limited to predefined weights like 400 or 700, but can use any value between the extremes – such as 350, 475, or 625.

The most important standardized axes are wght (Font Weight, the stroke thickness), wdth (Font Width, the character spacing from narrow to wide), opsz (Optical Size, optimized for different font sizes), slnt (Slant, the obliqueness for oblique styles), and ital (Italic, true italic style with its own glyphs). Some fonts additionally offer custom axes like Grade, Contrast, or even experimental axes for special effects.

Control is primarily via the CSS property font-variation-settings:

body {
  font-variation-settings: "wght" 350, "wdth" 100, "opsz" 18;
}

This code sets the weight to 350, the width to 100% (standard), and the optical size to 18. This allows not only fine gradations instead of fixed jumps, but also opens up design possibilities that were simply not realizable with static fonts.

Performance: Fewer Files, Faster Load Times

The performance gain of Variable Fonts is one of the most convincing arguments for their use. In traditional web projects, you had to load a separate file for each font variant. A typical setup might look like this:

Inter-Regular.woff2       (approx. 45 KB)
Inter-Medium.woff2        (approx. 48 KB)
Inter-Bold.woff2          (approx. 52 KB)
Inter-Black.woff2         (approx. 55 KB)

This totals about 200 KB of font data, distributed across four separate HTTP requests. Each request costs time, for DNS lookup, connection setup, TLS handshake, and the actual download. In times of mobile connections with high latency, this adds up to noticeable delays.

With Variable Fonts, this reduces to a single file:

Inter-Variable.woff2      (approx. 120 KB)

The file is often even smaller than the sum of individual static fonts because glyph data is reused internally. At the same time, it contains not just four, but theoretically infinite weights and that is any value between 200 and 900.

The advantages are measurable. Fewer HTTP requests mean faster load times, especially on connections with high latency (3G, 4G). The lower total data volume reduces data consumption, which is crucial for mobile users. A better caching strategy is possible because only one file needs to be cached, not four or more. And finally, Core Web Vitals improve and that especially First Contentful Paint (FCP) and Largest Contentful Paint (LCP), because texts can be rendered completely faster.

Especially for performance-critical web apps, dashboards, or content sites with large reach, this is a real gain. Every saved millisecond in loading directly affects the user experience.

Modern Usage: CSS Custom Properties for Font Axes

The combination of Variable Fonts with CSS Custom Properties enables a systematic, scalable typographic system. Instead of setting axis values directly in component styles, you define central design tokens that serve as a single source of truth. These tokens can then be adjusted project-wide or theme-wide without having to touch individual components.

The approach is simple but effective. You define typographic variables in :root or in theme-specific scopes:

:root {
  --wght-regular: 350;
  --wght-medium: 500;
  --wght-bold: 700;
  --wght-black: 850;

  --opsz-body: 16;
  --opsz-heading: 32;
  --opsz-display: 48;
}

These values are not arbitrary but follow the project’s visual hierarchy. A weight of 350 is often more readable than the standard 400, especially on high-resolution displays. A value of 850 for headlines creates more visual presence than the usual 700 without appearing overly heavy.

Using these tokens in the styles is then straightforward:

body {
  font-variation-settings: "wght" var(--wght-regular), "opsz" var(--opsz-body);
}

h1, h2 {
  font-variation-settings: "wght" var(--wght-bold), "opsz" var(--opsz-heading);
}

.display-title {
  font-variation-settings: "wght" var(--wght-black), "opsz" var(--opsz-display);
}

This approach has several advantages. First, it creates a scalable, systematic typographic foundation that is consistent across the entire project. Second, weights and optical sizes can be centrally adjusted, for example if the design team decides that headlines should appear slightly stronger. Third, it enables theme switching e.g. for Light/Dark Mode or brand variants, you can simply define different values for the same variables. And fourth, it is maintainable and documented because the variable names clearly communicate their function.

Context-Dependent Typography in Real Interfaces

Variable Fonts make it possible to precisely tailor typography to the context. A sidebar has different design requirements than a hero area. In a compact sidebar, headlines must appear concise and space-saving, while a marketing page emphasizes visual impact and presence. With Variable Fonts, this can be solved cleanly technically without loading different fonts.

A sidebar should appear more compact, headings should be more emphasized but not take up too much space. Here, a combination of moderate weight, slightly reduced width, and adjusted optical size is appropriate:

.sidebar h2 {
  font-variation-settings:
    "wght" 600,
    "wdth" 90,
    "opsz" 24;
}

The weight of 600 provides sufficient visual presence without being too dominant. The width of 90% (instead of 100%) makes the text more compact and saves horizontal space. The optical size of 24 is optimized for medium font sizes and ensures that characters remain readable even in limited space.

For a marketing page, on the other hand, different priorities are important. Here, visual impact, brand presence, and emotional appeal count. The hero title should appear powerful but not overloaded:

.hero-title {
  font-variation-settings:
    "wght" 750,
    "wdth" 105,
    "opsz" 48;
}

A weight of 750 is heavier than Bold (700) but not as extreme as Black (900). It appears powerful without being aggressive. The width of 105% makes the characters wider and gives the title more horizontal presence. The optical size of 48 is optimized for large display fonts and ensures that glyphs appear more elegant and finer at large sizes.

This turns typography into a flexible design tool that can be precisely adjusted to each context, without loading additional font files or writing complex overrides.

Fluid Weight – Dynamic Scaling for Responsive Typography

Variable Fonts open up a completely new possibility for responsive typography. While previously you had to switch between different font weights at breakpoints (for example from Regular to Bold), Variable Fonts allow fluid transitions. This means: The weight of a font can change continuously with the viewport width, without hard jumps.

The technique is elegant and uses clamp() or viewport-based units in combination with font-variation-settings:

h1 {
  font-variation-settings: "wght" clamp(500, 5vw, 800);
}

What happens here? At very narrow viewports (mobile), the heading has a weight of 500. This makes it readable but not too heavy, so it doesn’t appear overloaded even on small screens. As the viewport width grows, the weight increases linearly. The value 5vw means 5% of the viewport width. At a 1000px wide viewport, this corresponds to 50 (5% of 1000px = 50px, interpreted as a numeric value), at 1600px it’s 80. On large desktop screens, the weight finally reaches 800, powerful and present, matching the larger visual area.

This is a subtle but noticeable effect. Large headings appear stronger and more dominant on desktop, while they appear lighter and airier on mobile. Crucially: The font never appears disproportionate or exaggerated. The transition is organic and adapts to the available space.

This technique works particularly well for headlines, hero texts, and display typography where visual impact is important. For body text, it is less suitable because readability is a priority there and too much variation can be disruptive. But for design accents, Fluid Weight is a powerful tool that works without JavaScript or media queries and yet responds perfectly to the context.

Another advantage: Fluid weights can be combined with other fluid values, such as font-size: clamp(...) or line-height: clamp(...). This creates a fully responsive typographic system that organically adapts to any screen size.

Optical Sizing – Often Forgotten, But Extremely Important

Optical Sizing is one of the most underestimated features of Variable Fonts. The opsz axis allows the font to automatically adapt to optimal readability for the respective size. The principle comes from classical typography, where you used different cuts for small font sizes (such as in footnotes) than for large headings. Small fonts need more stroke weight, more open forms, and larger inner spaces to remain readable. Large fonts, on the other hand, can be finer, more elegant, and more detailed.

Variable Fonts with an opsz axis automate this process. You can either let the browser take control:

body {
  font-optical-sizing: auto;
}

This works well if the font is well-designed and brings sensible defaults. The browser then automatically selects the appropriate optical size based on the current font-size.

For more control, you can set the optical size manually:

body {
  font-variation-settings: "opsz" 14;
}

Here the optical size is fixed at 14, which is ideal for body text in the range of 14-16 pixels. The glyphs are more robust, the stroke weight is more consistent, and the inner spaces are large enough to remain readable even at smaller sizes or on low-resolution screens.

For large headings, you should choose a larger optical size:

h1 {
  font-variation-settings: "opsz" 48;
}

What happens technically? At smaller optical sizes (e.g. 14), the font becomes wider and more robust. The stroke weight is more uniform and the inner spaces of the letters are larger. This prevents letters like “e” or “a” from running together or becoming illegible at small font sizes. At larger optical sizes (e.g. 48), the font becomes more elegant and finer. The stroke weight varies more strongly (more contrast between thin and thick lines), and the details are more precise. This gives large headlines more expression and personality.

An often underestimated feature that makes the difference between “works” and “looks professional”. Especially in modern design systems that must cover both small UI texts and large marketing headlines, Optical Sizing is a decisive factor for consistent quality across all font sizes.

Interpolations and Animations – Soft Transitions Instead of Hard Jumps

One of the most fascinating properties of Variable Fonts is the ability to interpolate seamlessly between different styles. Since all variants are defined as continuous axes within a single font file, transitions can be animated. This opens up design possibilities that were simply not realizable with static fonts.

The transitions can affect various axes. From Regular to Bold, from Condensed to Expanded, or even from Roman to Italic. Since the values are continuous, no hard jumps occur, but organic, flowing transformations.

With CSS transitions, such transitions can be elegantly implemented:

.button {
  font-variation-settings: "wght" 500;
  transition: font-variation-settings 160ms ease;
}

.button:hover {
  font-variation-settings: "wght" 650;
}

What happens here is subtle but effective. When hovering over the button, the font weight increases from 500 to 650. The transition lasts 160 milliseconds and runs with an ease curve, which feels natural and responsive. The result: The button not only looks visually different on hover, but the change is noticeable. This creates a high-quality microinteraction feeling that makes interfaces more lively and interactive.

Important: The animation should be subtle. Too large weight jumps (for example from 300 to 900) or too long transitions appear unnatural and can even be irritating. A weight difference of 100-200 units over 120-200 milliseconds is ideal in most cases.

Such animations work particularly well with interactive elements like buttons, links, tabs, or navigation items. They give the user visual feedback and reinforce the feeling that the interface responds to interactions. And the best part: It’s performant. Since only CSS properties are animated, the animation runs directly on the GPU without JavaScript overhead.

Another application area is scroll animations. You could couple the weight of a heading with the scroll position, so it becomes lighter or heavier when scrolling. Or you could adjust the width of a navigation item when it becomes active. The possibilities are diverse, and with Intersection Observer or CSS Scroll-Driven Animations, such effects can be implemented today without large JavaScript libraries.

Variable Fonts in Design Systems

A modern design system benefits enormously from Variable Fonts. They solve several structural problems that repeatedly occur in traditional typography setups. Instead of managing separate font files for each weight variant (Light, Regular, Medium, Semibold, Bold, Black), you only need a single one. This reduces not only the data volume but also the organizational complexity.

In traditional design systems, you often had to make compromises. Do you really want to load six different font weights just to have finer gradations? Or do you limit yourself to Regular and Bold, but accept that the visual hierarchy becomes coarser? With Variable Fonts, this question no longer arises. You can define any number of weights without loading additional files.

This enables finer gradations. Instead of just 400 (Regular) and 700 (Bold), you can define intermediate steps like 450, 500, 550, 600, or 650. This allows more precise visual hierarchies. A subheadline could be designed with 550 and thus slightly more emphasized than Regular but less dominant than Bold. A call-to-action button could use 625, that would be strong enough to stand out but not as heavy as 700.

A typical token set for a design system could look like this:

:root {
  --font-wght-text: 350;
  --font-wght-ui: 450;
  --font-wght-subheading: 550;
  --font-wght-heading: 700;
  --font-wght-display: 800;
}

These tokens can then be used across components:

h2 {
  font-variation-settings: "wght" var(--font-wght-subheading);
}

.button {
  font-variation-settings: "wght" var(--font-wght-ui);
}

.hero-title {
  font-variation-settings: "wght" var(--font-wght-display);
}

The advantages are diverse. Fewer font families and files mean simpler asset management and faster onboarding for new team members. Consistent scales across all components ensure visual cohesion. Finer gradations enable more differentiated hierarchies without loading new font files. Flexible brand versions can be easily realized. For white-label products or subbrands, you can simply define different weight values. And the reduced complexity makes the system more maintainable and robust.

Another point: Variable Fonts are perfect for multi-brand design systems. If you serve multiple brands with a common design system, you can use the same Variable Font file but define different weight values for each brand. Brand A might use 350 for body text, Brand B uses 400. The technical basis remains identical, only the typographic tokens change. This is typographic precision on a level that was simply not possible before.

Limits and Challenges of Variable Fonts

Despite all advantages, there are limits and challenges that you should be aware of. Variable Fonts are not the universal solution for every typographic requirement, and there are situations where static fonts are the better choice.

The first limitation concerns axis support. Not every Variable Font supports all axes. Some only offer wght, others additionally wdth and opsz, still others have custom axes. Before deployment, you must check which axes the chosen font actually brings. Tools like the Variable Fonts section of the browser DevTools or online tools like Wakamai Fondue help with this.

The second challenge is the quality of the font design. A Variable Font is only as good as its interpolations. If the master designs are not carefully coordinated, intermediate values can look strange. Some fonts have unclean transitions where glyphs suddenly appear misshapen or inconsistent at certain weights. Here, only testing helps. You should try different values and visually check whether the interpolations work cleanly.

The browser support is very good today. All modern browsers support Variable Fonts (Chrome 66+, Firefox 62+, Safari 11+, Edge 17+). However, there are still users with older browsers, especially on older mobile devices or in enterprise environments with outdated browser versions. For these cases, you should define a fallback:

@supports (font-variation-settings: normal) {
  body {
    font-family: "InterVariable", sans-serif;
    font-variation-settings: "wght" 350, "opsz" 16;
  }
}

@supports not (font-variation-settings: normal) {
  body {
    font-family: "Inter", sans-serif;
    font-weight: 400;
  }
}

This ensures that even users with older browsers get readable typography, just with static fonts. Alternatively, you can also choose a progressive approach where you load static fonts as a base and layer Variable Fonts on top as an enhancement.

Another challenge is rendering on very old devices. On some older smartphones or low-end devices, the rendering of Variable Fonts can vary slightly. The differences are usually minimal, but in perfectionist design teams this can lead to discussions. Here it helps: Prioritization. For the vast majority of users, Variable Fonts work perfectly. For the small minority with old devices, you can define a fallback.

One last limitation: License costs. Not all Variable Fonts are free. Some commercial fonts charge higher license fees for Variable variants than for static weights. This must be considered in budget planning. However, there are also excellent free Variable Fonts like Inter, Recursive, Roboto Flex, or the Google Fonts collection, which are completely sufficient for most projects.

For modern web projects, however, the use of Variable Fonts is recommended in the vast majority of cases. The performance advantages, design flexibility, and technical elegance far outweigh the limitations.

Complete Implementation for a Modern Project

A clean implementation of Variable Fonts combines all discussed aspects into a coherent system. It starts with the correct @font-face declaration, which tells the browser which axes are available and which value ranges they cover. Then follow design tokens for consistent weights and optical sizes. Finally, these tokens are used in the actual styles.

The @font-face declaration is the starting point:

@font-face {
  font-family: "InterVariable";
  src: url("/fonts/InterVariable.woff2") format("woff2-variations");
  font-weight: 200 900;    /* wght axis range */
  font-stretch: 75% 125%;  /* wdth axis range */
  font-style: normal;
  font-display: swap;      /* Prevent FOIT */
}

Here you define the font family, the source (ideally as woff2-variations for optimal compression), the available axis ranges, and the display strategy. font-display: swap ensures that text is displayed immediately with a fallback font and then switches to the Variable Font once it is loaded. This prevents Flash of Invisible Text (FOIT) and improves perceived performance.

The design tokens form the second layer:

:root {
  /* Weight tokens */
  --font-text: 350;
  --font-ui: 450;
  --font-subheading: 550;
  --font-heading: 700;
  --font-display: 850;

  /* Optical size tokens */
  --opsz-body: 16;
  --opsz-ui: 18;
  --opsz-heading: 32;
  --opsz-display: 48;
}

These tokens are semantically named. --font-text is for body text, --font-ui for UI elements like buttons and labels, --font-subheading for subheadings, --font-heading for main headings, and --font-display for large hero texts. The optical sizes are correspondingly tuned to the typical font sizes of the respective contexts.

The application is then straightforward:

body {
  font-family: "InterVariable", system-ui, sans-serif;
  font-variation-settings: "wght" var(--font-text), "opsz" var(--opsz-body);
  font-feature-settings: "kern" 1, "liga" 1;
}

h1 {
  font-variation-settings: "wght" var(--font-heading), "opsz" var(--opsz-heading);
}

.hero-title {
  font-variation-settings: "wght" var(--font-display), "opsz" var(--opsz-display);
}

button, .btn {
  font-variation-settings: "wght" var(--font-ui), "opsz" var(--opsz-ui);
}

Additionally, font-feature-settings activates useful OpenType features like kerning and ligatures that further improve readability.

This is a modern, clean, performant typography architecture. It is maintainable because all values are centrally defined. It is scalable because new components can simply use the existing tokens. It is performant because only a single font file is loaded. And it is flexible because you can precisely tune weights and optical sizes to each context.

Conclusion

Variable Fonts represent a fundamental advance in web typography. They make typography more flexible, precise, and performant than was ever possible with static fonts. The technical advantages are measurable. Fewer HTTP requests, smaller file sizes, and faster load times lead to better Core Web Vitals and a noticeably improved user experience.

But the real strength of Variable Fonts lies in the design freedom they open up. Finer weight gradations enable more differentiated visual hierarchies. Optical Sizing ensures optimal readability across all font sizes. Fluid weights and animations create organic, responsive typography that elegantly adapts to the context. And integration into modern design systems with CSS Custom Properties makes the entire system maintainable, scalable, and future-proof.

The challenges are manageable. Browser support is excellent today, and for the few remaining edge cases, clean fallbacks can be defined. Quality depends on font design, but with careful selection and testing, excellent results can be achieved. And while some commercial fonts incur license costs, there is also a growing number of excellent free Variable Fonts.

For modern web projects, Variable Fonts are today the standard, not the exception. They simplify design systems, reduce technical complexity, and open up design possibilities that were simply not realizable before. The future of web typography is variable and that’s a good thing.


☕ Buy me a coffee

If you enjoy my articles and they help you in your work, I would appreciate a "coffee" and a few kind words from you.

Buy me a coffee

Previous Post
Door 17 – CSS Color Level 5
Next Post
Door 15 – Modern Typography in CSS

Comments