Fonts

Applies to perf.fonts.

Covers perf.fonts.

Fonts are the quietest performance problem on a site, because Lighthouse has no font audit. A page can score 100 while shipping half a megabyte of typefaces, so this one has to be checked by looking.

The rules

woff2 only. Every browser in use supports it. Shipping woff alongside is dead weight; shipping .ttf or .otf to a browser is worse, because those are the uncompressed desktop formats. An unsubset variable font in .ttf can be over 400 KB on its own - roughly the entire budget for a page, spent on letterforms.

Self-host. A third-party font host adds a DNS lookup, a TLS handshake and a render-blocking stylesheet before the first character can be drawn. It is also a data protection question for a French client, and one that has been litigated.

Subset. Most sites use Latin, some punctuation and a currency symbol. A full font carries Cyrillic, Greek, Vietnamese and a few thousand glyphs nobody will ever type. Subsetting to the characters actually used routinely cuts a font by 80 to 95 percent.

Watch two traps when subsetting a French site: the accented characters and the ligatures. Check that œ, à, é, è, ê, ç, ù and the guillemets « » all survive the subset. A missing glyph falls back to another font mid-word and is easy to miss in review.

font-display: swap. Text is readable in a fallback immediately and reflows when the font arrives. The alternative is invisible text for up to three seconds, which is the worst possible outcome if that text is the LCP element.

Preload the one font used above the fold. One, not all of them.

<link rel="preload" href="/fonts/brand-regular.woff2" as="font" type="font/woff2" crossorigin>

The crossorigin attribute is required even for same-origin fonts. Without it the browser fetches the file twice, and the preload makes things worse rather than better.

The reflow

swap trades invisible text for a visible reflow, and that reflow is a layout shift if the fallback has different metrics. Fix it with a metric-matched fallback rather than by removing swap:

@font-face {
  font-family: "Brand Fallback";
  src: local("Arial");
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
}

body { font-family: "Brand", "Brand Fallback", sans-serif; }

Tune the percentages until the fallback occupies the same space. Done properly the swap is barely visible and CLS stays at zero.

Budget

No font file over 100 KB. Two weights of one family is usually enough for a marketing site; each additional weight is another file on the critical path. A variable font can be a good trade when three or more weights are genuinely used, and a bad one when it ships the full axis range to deliver two.

Checking it

Open the network panel, filter by font, and read the sizes and the formats. That is the whole test, and it takes ten seconds. Nothing else in the audit chain will tell you.