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.
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.
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' })
ID: performance-load.bundle.font-loading
Severity: medium
What to look for: Count all custom font declarations: @font-face rules in CSS files, Google Fonts <link> tags, and framework font APIs (e.g., next/font). For each font declaration, check the font-display value. Classify as: (a) swap or optional (good), (b) block or auto (blocking), or (c) missing font-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: swap or font-display: optional. No more than 0 fonts use block or omit font-display. Total font payload is under 500KB. Framework font APIs (next/font) that default to swap satisfy 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, omit font-display entirely (defaults to blocking), or total font payload exceeds 500KB without subsetting.
Skip (N/A) when: No custom fonts detected — 0 @font-face rules, 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.