Lighthouse audit font-display · Performance

Ensure text remains visible during webfont load: the font-display fix

View raw .md for LLMs / your notes
Quick answer: This audit fails when a web font loads without a font-display strategy, letting browsers hide text while the font downloads. Fix it by adding font-display: swap to every @font-face rule, or the display=swap parameter to Google Fonts URLs. Use optional for non-branding fonts to avoid layout shift entirely.

This audit fails when a web font is loaded without a font-display strategy, which lets browsers hide your text (sometimes for several seconds) while the font file downloads. The fix is one CSS descriptor, but choosing the right value matters.

TL;DR

What does "ensure text remains visible during webfont load" mean?

Lighthouse checks every @font-face rule the page uses. If a rule has no font-display descriptor (or uses block), the browser is allowed to render the text as invisible while the font downloads: up to 3 seconds in most browsers, indefinitely in some older ones. On a slow connection your visitors stare at a page with headings and paragraphs that are physically there but painted in transparent ink.

The audit passes when every font the page loads declares a strategy that keeps text visible: swap, fallback, or optional.

What is font-display: swap?

font-display: swap tells the browser: render text immediately in a fallback system font, then swap in the web font whenever it arrives.

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-var.woff2') format('woff2');
  font-weight: 100 900;
  font-display: swap;
}

The text is readable from the first paint. The cost: when the web font arrives, the text re-renders, and if the two fonts have different metrics, the page can shift (see the CLS section below).

How do I fix it?

Where the fix goes depends on where the font comes from:

Self-hosted fonts: add font-display: swap to each @font-face rule, as above. This is the case Lighthouse flags most often.

Google Fonts: add the display parameter to the stylesheet URL:

<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">

Without &display=swap, Google serves @font-face rules with no descriptor and the audit fails even though the CSS is not yours.

Font services (Adobe Fonts, etc.): most have a display setting in the project config. Adobe Fonts exposes it per-project; set it to swap.

Third-party CSS you cannot edit: override the face locally. Declare your own @font-face with the same font-family name, your own src pointing at the same file, and a font-display value. If you truly cannot, preloading the font file (below) shrinks the window where the strategy matters.

Should I use swap, fallback, or optional?

ValueBehaviorUse when
swapFallback text immediately, swap whenever the font arrivesBranding fonts that must eventually show. The default fix.
fallback~100 ms invisible, then fallback; swaps only if the font arrives within ~3 sMiddle ground: avoids a jarring swap 8 seconds in
optional~100 ms invisible, then fallback; the browser may skip the web font entirely on slow connectionsBody text where the system font is acceptable. Best for performance and CLS.
blockUp to 3 s invisible, then fallbackAlmost never. Icon fonts are the one honest case (see mistakes).

The honest recommendation: swap for the one or two fonts that carry your brand, optional for everything else. If a font is so close to a system font that users would not notice it being skipped, optional means your slowest visitors simply never pay for it.

Does font-display: swap cause layout shift?

It can. When the fallback font and the web font have different character widths or line heights, the swap moves content, and that movement counts toward Cumulative Layout Shift. Two mitigations:

  1. Tune the fallback with font metric overrides so it occupies the same space as the web font:
@font-face {
  font-family: 'Inter-fallback';
  src: local('Arial');
  size-adjust: 107%;
  ascent-override: 90%;
}

Tools like Capsize or the Fontaine build plugin compute these numbers for you.

  1. Preload the critical font so it usually arrives before first paint, making the swap invisible:
<link rel="preload" as="font" type="font/woff2" href="/fonts/inter-var.woff2" crossorigin>

Preload only the one or two files used above the fold. Preloading every weight defeats the purpose.

What are common font-display mistakes?

How do I verify the fix?

  1. Re-run Lighthouse: "Ensure text remains visible during webfont load" should move to the passed list.
  2. In DevTools, throttle the network to Slow 3G, hard-reload, and watch the first paint: text should be readable immediately in a fallback font.
  3. If you chose swap, check the CLS audit did not regress; if it did, add metric overrides to the fallback.

Related audits


Audit your URL at https://lighthouse-md.com.

Audit your page now

Paste your URL, get scores plus a CLAUDE.md plan for Claude Code.

Run audit →