Fonts use font-display: swap or optional, not block
Why it matters
A font loaded without font-display: swap defaults to auto behavior — which blocks text rendering for up to 3 seconds while the font file downloads. During this Flash of Invisible Text (FOIT), users see a blank page where content should be. Google Fonts requests without the &display=swap parameter apply this blocking behavior by default. A single Google Fonts link loading 4 weights without swap can delay text visibility by 300–800ms on a 4G connection, directly harming LCP. ISO 25010 performance-efficiency.time-behaviour captures this as a preventable delay in delivering the primary content to the user.
Severity rationale
Medium because blocking font-display causes Flash of Invisible Text — a visible content delay for real users — but does not prevent the page from eventually loading.
Remediation
Add font-display: swap to every @font-face declaration, and append &display=swap to all Google Fonts URLs. For Next.js, use next/font which applies swap by default and eliminates the external request entirely.
/* Before — blocks rendering for up to 3s */
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
}
/* After — shows fallback font immediately, swaps when ready */
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom.woff2') format('woff2');
font-display: swap;
}
<!-- Before -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700" rel="stylesheet" />
<!-- After -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet" />
// Next.js — preferred: eliminates external request, swap by default
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'], display: 'swap' })
Detection
-
ID:
font-loading -
Severity:
medium -
What to look for: Count all custom font declarations:
@font-facerules in CSS files, Google Fonts<link>tags, and framework font APIs (e.g.,next/font). For each font declaration, check thefont-displayvalue. Classify as: (a)swaporoptional(good), (b)blockorauto(blocking), or (c) missingfont-display(defaults to blocking). Also measure total font file size. Enumerate: "X font declarations found, Y use font-display: swap or optional." -
Pass criteria: 100% of custom font declarations use
font-display: swaporfont-display: optional. No more than 0 fonts useblockor omitfont-display. Total font payload is under 500KB. Framework font APIs (next/font) that default toswapsatisfy this requirement. Report: "X of Y font declarations use swap or optional. Total font payload: ZKB." -
Fail criteria: 1 or more custom font declarations use
font-display: block, omitfont-displayentirely (defaults to blocking), or total font payload exceeds 500KB without subsetting. -
Skip (N/A) when: No custom fonts detected — 0
@font-facerules, 0 Google Fonts links, 0 framework font API usages found. Only system fonts are used. -
Detail on fail:
"2 of 3 custom fonts in globals.css use font-display: auto (blocking) — Inter and Roboto lack explicit swap"or"Google Fonts link imports 4 weights without display=swap parameter — 320KB font payload blocks rendering" -
Remediation: Use font-display swap:
/* Before — blocks rendering */ @font-face { font-family: 'CustomFont'; src: url('/font.woff2') format('woff2'); /* font-display defaults to 'auto' which acts like 'block' */ } /* After — swap is immediate */ @font-face { font-family: 'CustomFont'; src: url('/font.woff2') format('woff2'); font-display: swap; }Or for Google Fonts:
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet" />Consider using system fonts or Google Fonts, which are globally cached.
External references
- iso-25010:2011 · performance-efficiency.time-behaviour — Time Behaviour
Taxons
History
- 2026-04-18·v1.0.0·Initial import from performance-load·automated