Fix Guide

How to Fix Slow Web Fonts with Better Optimization

A step by step guide to identifying heavy fonts, switching to WOFF2, preloading the right files, and keeping text visible while fonts load.

Team PagePatcher
Team PagePatcher
5 min read
How to Fix Slow Web Fonts with Better Optimization

Web fonts are a sneaky performance problem. A single font family with four weights and italics can easily ship hundreds of kilobytes, and every variant is render blocking by default. Until the browser downloads at least one font file, your text either stays invisible or flashes through fallbacks. The fix is a short checklist.

Work through these five steps in order. Once your fonts are tidy, move on to render blocking CSS and slow JavaScript, or read our complete guide to page loading speed for the wider picture.

The fix path differs depending on how you build. If you ship a custom site, you control the @font-face rules and preload tags directly and the examples below apply as written. If you build in Webflow, Framer, or another visual tool, your font configuration lives in the builder's font settings panel. The principles are the same (fewer weights, WOFF2 format, swap behavior for fallbacks, self-hosting where possible) but you apply them by editing builder settings rather than CSS.

Step 1: Find the heaviest fonts you ship

Open DevTools, go to the Network tab, filter by Font, and reload. Every font file the page downloads appears in the list with its exact size. Sort by transfer size and note anything above a hundred kilobytes.

For multi-page sites, paste your URL into our Website Optimizer. We group fonts by family, flag heavy files, and show which formats you are still serving. Watch for families that ship every weight when only a couple are actually used on the page. This is the single most common waste we see on no code sites, where it is easy to select every weight in the font picker once and forget about it.

Step 2: Switch every font to WOFF2

WOFF2 is the smallest widely supported font format, and browser support per caniuse.com is universal for anything you would actually target. Legacy TTF, OTF, and WOFF files are larger for no benefit on modern browsers.

If you have a TTF or OTF source, run it through fonttools, a Python font manipulation library that ships with command-line utilities, to produce a WOFF2 build. Most font foundries now ship WOFF2 directly, and Google Fonts serves WOFF2 by default when the requesting browser supports it.

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
}

Step 3: Set font-display: swap

By default, browsers hide text while a custom font is loading. The result is a flash of invisible text that wrecks your Largest Contentful Paint score. The fix is one line per @font-face rule.

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-regular.woff2") format("woff2");
  font-display: swap;
}

With swap, the browser renders your text in a fallback font immediately, then repaints when the real font arrives. Read the MDN reference for font-display for the other values. In practice, swap is the right default for body text and optional is a sensible choice for decorative display fonts that you can live without.

In Webflow, font-display is set to swap for custom fonts by default and cannot be edited through the UI. In Framer, the platform manages font-display for you and no action is needed. If you see a flash of invisible text on one of these platforms, the cause is usually elsewhere, either a preload missing or a font file blocked by a slow third party origin.

Step 4: Preload your critical fonts

The browser discovers font files only after it parses your stylesheet. By that point, you have already spent a round trip on the CSS itself. Preloading tells the browser to start fetching the font in parallel with the stylesheet.

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

Preload the one or two fonts used in your hero, headline, and first paragraph. The crossorigin attribute is required even for same-origin fonts because font loading uses anonymous CORS. See web.dev's preload walkthrough for the full pattern.

Step 5: Self-host or subset your fonts

Google Fonts is convenient, but each family adds a DNS lookup, a TLS handshake, and a cross-origin request to fonts.googleapis.com. Self-hosting removes all three. Download the WOFF2 files, drop them in your public directory, and point your @font-face rules at the local paths.

If you must keep Google Fonts, at least trim the request to the weights you actually use. The fonts.googleapis.com URL takes explicit weight and style parameters, so a page using only regular and bold should not be loading seven extra weights.

For sites that only use Latin characters, subsetting cuts font files to a fraction of their original size. Tools like Glyphhanger scan your content and produce a subset containing only the glyphs your page needs.

On Webflow, upload the WOFF2 files you want to use in the custom font uploader and reference them like any built-in font. Framer handles self-hosting of Google Fonts automatically, so the only lever left is trimming the weights you have selected. In both cases, start by deleting any font family or weight you are not actually using, which is the fastest win available before you touch anything technical.

Once your fonts are under control, run your page through the Website Optimizer again. Font weight should be down, there should be no flash of invisible text, and your LCP should move in the right direction.

Run the fix automatically

Let PagePatcher find the exact issues on your site.

Paste your URL and we surface every oversized asset, render blocker, and missing optimization, with concrete steps to fix each one.

Web Fonts Optimization: WOFF2, Preload, Font Display Guide | PagePatcher