Snippets / Typography /
Responsive Variable Font Axes
Drive variable font axes — weight, optical size, letter-spacing — directly from viewport width using clamp(), no media queries or JavaScript needed.
scales with vw
auto via size
scales with vw
Quick implementation
/* Responsive weight: light on mobile, bold on desktop */
.heading {
font-variation-settings:
'wght' clamp(300, 300 + 40 * ((100vw - 320px) / 880px), 700);
}
/* Optical size follows font size automatically */
.text {
font-size: clamp(1rem, 2.5vw, 2.5rem);
font-optical-sizing: auto; /* sets opsz axis to match font-size in pt */
}
/* Letter-spacing tightens at large sizes, opens at small sizes */
.display-heading {
font-size: clamp(2rem, 6vw, 5rem);
letter-spacing: clamp(-0.04em, -0.04em + 0.06 * ((100vw - 320px) / 880px) * 1em, 0.02em);
}Prompt this to your LLM
Includes role, constraints, two framework variants, and edge cases to handle.
You are a CSS typography expert. Demonstrate how to drive variable font axes responsively using clamp() — no JavaScript, no media queries.
Requirements:
1. Use font-variation-settings: 'wght' clamp(300, ..., 700) to interpolate weight from light on mobile (320px) to bold on desktop (1200px). The clamp math is: clamp(min, min + range * ((100vw - 320px) / (1200px - 320px)), max).
2. Show font-optical-sizing: auto on a fluid-size heading — explain that the browser sets the opsz axis automatically to match the rendered point size.
3. Show letter-spacing tightening at large sizes using clamp(-0.04em, ..., 0.02em) — tight tracking at display sizes, open tracking at small sizes.
4. Use a variable font that has both wght and opsz axes (e.g. DM Sans from Google Fonts: family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,700).
Constraints:
- The clamp() interpolation formula must be unitless inside font-variation-settings — cast 100vw arithmetic carefully.
- Include a note that font-variation-settings overrides all other variation axes, so always set every axis you care about explicitly.
- Add a fallback: if the font doesn't support wght axis, font-weight: clamp(300, ..., 700) still works for font-weight but won't animate smoothly.
Output HTML + CSS demonstrating all three techniques side by side.Why this matters in 2026
Variable fonts expose their design space as continuous numeric axes — weight, width, optical size, slant, and more. Combining these axes with clamp() lets you build a single typographic rule that adapts across every viewport without breakpoints. The result is typography that feels intentionally designed at every size, not just at the two or three breakpoints you thought to add media queries for.
The logic
The key formula is clamp(min, min + range * ((100vw - viewportMin) / (viewportMax - viewportMin)), max). Inside font-variation-settings the value must be a plain number, not a length, so the viewport arithmetic must produce a unitless result. For font-size and letter-spacing you can use clamp() directly with em or rem units. font-optical-sizing: auto is the easiest win — the browser reads the computed font size and sets the opsz axis automatically, so you get optimised strokes at every size for free.
Accessibility & performance
Viewport-driven axes mean text is always appropriately weighted for its context — heavier on small, crowded mobile screens where fine hairlines disappear; lighter on large displays where heavy text feels oppressive. There is no JavaScript execution cost and no layout thrashing; the browser resolves clamp() during the style cascade. The only caveat is that font-variation-settings is not animatable by CSS transition when driven by viewport units, but resizing triggers a recalculation that is fully GPU-composited at paint time.