In our theme audits, custom fonts are the single most common cause of a poor LCP on otherwise fast sites. The mechanism is unforgiving: browsers delay rendering text (or render it invisibly) until the font arrives, and on mobile 4G a 300 KB font family costs you the LCP race. Here is the strategy stack we apply, in order of impact.
1. Stop loading fonts you do not use
Themes love shipping six weights across two families “for flexibility.” Check DevTools: if your site renders with three weights, the other three are pure waste. Disable unused weights in the theme panel or deregister them in code. One client cut font payload from 460 KB to 180 KB in ten minutes.
2. Preload only the font that paints first
Preloading tells the browser to fetch a specific font immediately, before CSS parsing finishes. Preload the one file covering your largest above-the-fold text — usually the 400-weight of your heading font. Preloading everything recreates the problem you are solving. The pattern:
<link rel="preload" href="/fonts/main-400.webp2.woff2" as="font" type="font/woff2" crossorigin>
Note crossorigin — even for same-origin fonts. It is the most common preload mistake we see.
3. font-display: swap — with judgment
swap renders fallback text immediately, then repaints when the webfont lands. It fixes invisible-text LCP penalties at the cost of a flash. For body text, swap is right. For a distinctive brand heading where flash is jarring, fallback can be the better trade — decide per family, not globally.
4. Subset and self-host
Latin subsets of most fonts drop 30–50% of glyph payload. Self-hosting (versus Google Fonts’ CDN) removes a third-party connection from your critical path — and matters for GDPR-minded European audiences. Self-hosted fonts also play nicer with the preload strategy above.
Measured results
Across six client sites where fonts were the LCP bottleneck: average LCP improvement of 0.4–0.9s after the full stack — unused weights removed, one file preloaded, swap enabled, latin subset self-hosted. That is often the difference between “needs improvement” and “good” in Core Web Vitals terms.
How this interacts with the theme
Good themes (GeneratePress, Kadence) expose per-weight loading and local hosting options. If your theme hard-codes Google Fonts with no toggle, that is a diagnostic signal — see the slow-theme walkthrough for where that sits in the bigger picture. The WordPress developer docs describe the correct registration APIs.
The one that paints your largest above-the-fold text — usually the regular weight of your heading font. Preload exactly one or two files, never the whole family. Font requests are always made in CORS mode. Without crossorigin on the preload, the browser fetches the file twice and your preload achieves nothing. It can cause a visible flash on distinctive brand fonts. Use swap for body text, and consider fallback for the one signature heading font if flash is unacceptable. Self-hosted with preloading is typically faster — it removes a third-party DNS/TLS handshake from the critical path. Google Fonts is fine when configured with preconnect. When fonts are the bottleneck, our client audits measured 0.4–0.9s LCP improvement from the full stack: fewer weights, one preload, swap, subsetting.Which font file should I preload?
Why does crossorigin matter on same-origin font preloads?
Is font-display swap bad for branding?
Self-hosting vs Google Fonts: which is faster?
How much can font fixes improve LCP?