Why Font Loading Still Feels Like a Losing Battle
Web fonts remain one of the weakest links in page performance. Developers who choose to use them are stuck with two unappealing options: hide text until the font arrives (FOIT) or show a fallback first and swap later (FOUT). Neither approach has emerged as a clear winner, and that's largely because both introduce their own problems — invisibility or layout shift.
The font-display property was supposed to hand this decision to developers instead of leaving it to browser defaults. In practice, it only formalized the existing trade-offs. When font-display: swap became the default on Google Fonts in 2019, many sites adopted it under the assumption that showing text quickly, even in a fallback face, was always the better performance choice. The reality is more complicated.
The core issue with swap is the "hydration effect": when the web font finally downloads, glyphs expand or contract, and the visible text shifts. That jarring reflow is precisely what Core Web Vitals and Cumulative Layout Shift metrics are designed to penalize. On many sites, including Smashing Magazine, the difference between the fallback render and the final web font render is substantial — fonts vary noticeably in size and spacing, causing content to move around the viewport.
Some developers, frustrated by these shifts, have moved back to font-display: block, accepting a short invisible period in exchange for a less disruptive final layout. Others have doubled down on self-hosting and subsetting fonts, preloading them so the fallback is visible only briefly. But neither strategy removes the fundamental tension.
The Optional Escape Hatch Has Its Own Cost
font-display: optional offers a third path: use the web font only if it's already downloaded by the time the page needs it; otherwise, stick with the fallback for the entire session. This avoids both FOIT and FOUT but effectively surrenders the web font on first visit. Reloads and subsequent navigations will use it once the download completes.
That trade-off might make sense for fonts that are genuinely non-essential — in which case deleting them entirely is even better for performance. But for sites where the font is part of the brand experience, shipping a first impression without it feels like a downgrade, even if it's hard to quantify. The perception that something is subtly off can have an impact that metrics alone won't capture.
Matching Fallback Fonts: The Current Workaround
The practical alternative is to make the fallback font look as close as possible to the web font, minimizing the shift when the swap happens. Tools like Monica Dinculescu's Font Style Matcher let you overlay two fonts and adjust settings until they align. The problem is that these adjustments — font-size, line-height, letter-spacing — can't be scoped to the fallback font alone with plain CSS.
That forces developers into JavaScript. Using the FontFace.load API, you can detect when the web font is ready and then apply or revert the compensating styles. It's not a huge amount of code, but it adds complexity. You also need to account for cached fonts that load instantly and for different fallback fonts across operating systems. On a site like Smashing Magazine, which lists multiple fallbacks to cover various system fonts, maintaining separate adjustments for each quickly becomes unwieldy.
A Declarative Fix on the Horizon
New @font-face descriptors proposed in CSS Fonts Module Level 5 aim to solve this by letting you declare fallback font adjustments directly in CSS, so the browser handles the swap logic. The original proposal included four descriptors: ascent-override, descent-override, line-gap-override, and advance-override. They mainly affected vertical metrics, leaving horizontal spacing to be handled separately with extra CSS.
Since then, the spec has evolved. advance-override has been dropped in favor of size-adjust, which applies a percentage scale factor to glyphs to bring the fallback's advance widths closer to the web font. Combined with the vertical overrides, this gives you a way to align fallback and web fonts across both axes.
Concretely, instead of pointing directly at a webfont in your font stack, you create an additional @font-face rule for the fallback, using local() to reference a system font:
@font-face {
font-family: 'Lato-fallback';
src: local('Arial');
size-adjust: 97.5%;
ascent-override: 92%;
}
You then reference Lato-fallback in place of Arial. The descriptor values tune how Arial is rendered so it more closely matches Lato. It's an extra rule to write, but it's far simpler than the JavaScript dance previously required. The four descriptors currently in the spec — size-adjust, ascent-override, descent-override, and line-gap-override — cover the main layout dimensions, with discussion ongoing for additional cases.
Tooling is emerging to take the guesswork out of choosing values. Malte Ubl has built an automatic calculator that, given a web font and fallback, derives the descriptor settings for you. The goal isn't pixel-perfect parity across every operating system — that's practically impossible. It's to reduce the visible gap enough that font-display: swap stops feeling like a worse option than blocking or opting out entirely.
Browser Support and the Road Ahead
The ascent-override, descent-override, and line-gap-override descriptors have been available in Chrome since version 87. The more significant size-adjust descriptor, however, has not yet shipped in any stable browser. It is currently available in Chrome Canary and in Firefox behind a flag, so the feature is not purely theoretical — it could land in the near term.
The CSS Fonts Module Level 5 specification still carries warnings that it is not ready for production use. That said, the specification is maturing, and there is a balance to strike: early testing and feedback help shape the implementation, but widespread adoption of an immature draft could stall progress. Chrome has indicated its intention to ship size-adjust in Chrome 92, scheduled for release on July 20, which suggests the feature is close to being production-ready.
For now, the practical guidance is to experiment with the demo in Chrome Canary, using a fallback font setup to see how much closer size-adjust can bring you to reducing the layout shift caused by font loading.
Further Reading
- Sticky Headers And Full-Height Elements: A Tricky Combination
- Webfonts And Performance: SmashingConf Videos
- Useful DevTools Tips and Tricks
- Reporting Core Web Vitals With The Performance API




