# Fonts use font-display: swap or optional, not block

- **Pattern:** `ab-002063` (`performance-load.bundle.font-loading`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002063
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002063)

## 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.

```css
/* 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;
}
```

```html
<!-- 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" />
```

```ts
// 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-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:

  ```css
  /* 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:

  ```html
  <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 performance-efficiency.time-behaviour

Taxons: performance

HTML version: https://auditbuffet.com/patterns/ab-002063
