How CSS font-size-adjust Preserves Fallback x-Height
When web fonts fail to load or swap dynamically, differences in
typeface proportions can cause jarring layout shifts and poor
legibility. The CSS font-size-adjust property solves this
issue by standardizing the perceived visual size—specifically the
lowercase "x-height"—across primary and fallback typefaces. By
dynamically scaling the font size based on character metrics rather than
arbitrary em-box heights, it ensures that fallback text remains visually
consistent and structurally stable.
The Problem: Mismatched Aspect Ratios
Different typefaces set at the exact same font-size
(such as 16px) often look radically different in visual
weight and scale. This disparity occurs because font-size
defines the total height of the font's design box (the em-box), not the
height of individual letters.
The legibility of a typeface is primarily determined by its x-height—the height of lowercase letters (such as "x", "a", or "e") relative to the total font size. The ratio of x-height to font size is called the aspect value:
\[\text{Aspect Value} = \frac{\text{x-height}}{\text{font-size}}\]
A font with a high aspect value (like Verdana, ~0.58) appears much
larger and wider than a font with a low aspect value (like Times New
Roman, ~0.45), even when both are set to 16px. If Verdana
is set as a fallback for a font with a low aspect value, the layout
expands unpredictably, resulting in severe Cumulative Layout Shift
(CLS).
How font-size-adjust
Works
The font-size-adjust property enables developers to lock
in a consistent aspect value. Instead of rendering text strictly at the
declared font-size, the browser dynamically recalculates
the font size for whatever font is currently active using the following
formula:
\[\text{Adjusted Font Size} = \text{Specified Font Size} \times \left( \frac{\text{Target Aspect Value}}{\text{Font's Actual Aspect Value}} \right)\]
If the primary font fails to load or is delayed, the browser scales the fallback font up or down until its x-height matches the target aspect value.
Implementation and Syntax
The property accepts either a numeric value representing the aspect ratio or modern metric-specific keywords.
1. Using a Numeric Value
To match x-heights, you define the aspect ratio of your preferred primary font:
body {
font-family: "CustomSans", Arial, sans-serif;
font-size: 1rem;
font-size-adjust: 0.52; /* The aspect value of CustomSans */
}If CustomSans (aspect value 0.52) loads,
the text renders at 1rem. If it fails, and the browser
falls back to Arial (aspect value 0.518), the
browser scales Arial by \((0.52 /
0.518)\), keeping lowercase letters at virtually the identical
height.
2. Using Modern Keywords (CSS Fonts Level 4)
Modern browser implementations allow you to extract the aspect value directly from the primary font or specify alternative reference metrics:
body {
font-family: "CustomSans", Arial, sans-serif;
font-size: 1rem;
font-size-adjust: from-font;
}The from-font value instructs the browser to
automatically read the x-height metric embedded in the primary font
file's tables and apply that ratio across all fallbacks.
You can also target metrics other than x-height:
cap-height: Normalizes the height of capital letters.ch-width: Normalizes the horizontal advance width of digits and characters (useful for monospace alignment).ic-width: Normalizes the width of ideographic glyphs (essential for CJK typography).
Practical Benefits
- Mitigates Layout Shift (CLS): Because lowercase heights and proportional line-heights remain stable during font-swapping, content reflow is significantly minimized.
- Preserves Visual Hierarchy: Headings and body copy retain their intended contrast and visual density regardless of network conditions or device font availability.
- Improves Accessibility: Fallback fonts that are naturally smaller will not degrade into illegibly tiny text when a web font fails.