Web Fonts: Keep Text Visible While Fonts Load
Custom web fonts are separate files that the browser only discovers once it has the CSS that uses them. Until they arrive, the browser has to decide what to do with the text: hide it, or show it in a fallback font and swap later. By default many browsers hide it for up to a few seconds, which on a slow connection means visitors see a page with empty spaces where the headings and paragraphs should be.
Why it matters
Invisible text delays the moment a page becomes readable, and when the largest element on screen is text, it delays Largest Contentful Paint too. Fonts that arrive late and swap in a very different fallback can also shift the layout, which counts toward Cumulative Layout Shift.
font-display
The font-display descriptor in each @font-face rule controls this behaviour:
| Value | What happens |
|---|---|
block |
text is hidden for a short period, then shown in the fallback until the font loads |
swap |
text shows in the fallback immediately and switches when the font arrives |
fallback |
a very short hidden period, then the fallback; the font is used only if it arrives soon |
optional |
like fallback, but the browser may skip the font entirely on slow connections |
auto |
the browser decides, which usually means block |
swap is the common choice for brand and body fonts. optional avoids layout shifts completely
and suits body text where the fallback is acceptable.
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-latin.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
}
How to fix
Google Fonts
Add display=swap to the stylesheet URL. Google then includes font-display: swap in every
@font-face rule it returns:
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap"
/>
Self-host your fonts
Serving fonts from your own domain avoids connecting to extra origins and gives you full control
over font-display and caching. Most open-source fonts, including those on Google Fonts, allow
self-hosting; check the licence for commercial fonts.
Preload the main font
Preloading lets the browser fetch a font before it has parsed the CSS that needs it. Preload only
the one or two files used on the first screen; preloading everything competes with more important
files. The crossorigin attribute is required for fonts, even on your own domain:
<link rel="preload" href="/fonts/inter-latin.woff2" as="font" type="font/woff2" crossorigin />
Use WOFF2 and subset
WOFF2 is supported by all modern browsers and is the most compact font format, so older formats
like TTF, EOT or SVG fonts are no longer needed. If your site uses one script, such as Latin,
serve a subset that contains only those characters. unicode-range in @font-face lets the
browser download a subset only when the page uses characters from it. A variable font can replace
several weight files with one.
WordPress
Many themes load Google Fonts from their options; look for a setting to self-host them or to set
the display behaviour. Recent WordPress versions include a Font Library for block themes that
stores fonts on your own site. Some optimisation plugins can also add font-display: swap to font
rules they find.
Fonts in CSS you don’t control
If a third-party stylesheet loads a font without font-display, you can’t change its rules. Ask
whether the provider offers a display option, or self-host the font instead.
How PerfoMetrix checks this
We read Lighthouse’s font display audit (font-display-insight) from the PageSpeed Insights
run we already make (mobile, simulated device). If Lighthouse rates it 0.9 or higher, or the page
uses no web fonts, the check passes; otherwise it needs attention. We show Lighthouse’s estimate,
such as “Est savings of 80 ms”, and the first five font files it lists.
This check is shown but doesn’t count toward the performance score: its effect is already measured by FCP and LCP, which are scored. No extra requests are made to your site.