How Much Are Your Fonts Costing Your Page Speed?

· 5 min read

After images, fonts are usually the heaviest thing a page downloads — and unlike images they block what the reader sees, because text cannot be drawn until the browser knows what to draw it in. Four decisions account for nearly all of the cost. Three of them cost nothing to get right.

One: the format

A WOFF2 is around 60% smaller than the .ttf it was made from, and every browser still receiving security updates reads it. If you are serving anything else, this is a free saving and it takes one conversion. Old snippets listing EOT, SVG and TTF fallbacks are shipping files nothing requests — see the format guide.

Two: the character set

This is the big one and the one almost nobody does. A font carrying Cyrillic and Greek makes an English-language site download two alphabets it will never draw. Cutting to Latin commonly halves the file and sometimes takes three quarters off it. Every font page here offers both, with the measured sizes on the buttons, and the subsetting post explains what is being removed.

Three: how many files

Four static weights is four downloads. The same family as a variable font is one file that is usually smaller than three of those four — which is why a variable font is a performance decision and not only a design one, as long as you actually use more than two weights. If you use exactly one weight, a static file is smaller.

The other half of this is discipline. Two families is a reasonable ceiling for most sites. Three is a decision to justify. A page loading five is usually a page where nobody has looked at the network tab.

Four: when the download starts

A font referenced from a stylesheet is not requested until the browser has parsed that stylesheet, which is already late. A rel="preload" as="font" crossorigin link in the head starts it in parallel instead. Preload only what is on the first screen — preloading everything makes the page slower, because the requests compete with each other.

Then decide what the reader sees in the meantime. font-display: swap shows fallback text immediately and swaps, at the cost of a visible shift. font-display: optional gives the font a very short window and gives up for that page view if it misses, so nothing ever shifts.

The layout shift nobody attributes to fonts

When the real font swaps in, every line of text re-measures. If the fallback is much narrower or wider, the page jumps — and Cumulative Layout Shift is a ranking signal, so this is not only an aesthetic problem.

The fix is to make the fallback closer in metrics to the real font, using size-adjust, ascent-override and descent-override on an @font-face rule that points at a local system font. It is fiddly and it is the difference between a visible jump and none.

A realistic target

  1. WOFF2 only. Delete every other format from your CSS.
  2. Latin cut unless you genuinely set another alphabet.
  3. One variable file, or two static weights. Not six.
  4. Preload what is above the fold, and nothing else.
  5. Set font-display deliberately rather than leaving it to the default.

Done properly, a page with one variable family in a Latin cut is spending somewhere between 20 and 60 KB on typography. Done carelessly, the same design costs half a megabyte. The design is identical either way, which is what makes this worth twenty minutes.

Measuring your own site in five minutes

Every number above is a guide. The one that matters is what your own pages actually fetch, and finding it takes one panel: open the browser’s developer tools, go to the network list, filter it to fonts, and reload with the cache disabled.

  1. Count the files. More than two or three on a first view is nearly always an accident — an italic nobody uses, a weight that exists only in the design file.
  2. Add up the transferred size, not the file size. A WOFF2 is already compressed, so the two are close, but a TTF served by mistake will show the difference immediately.
  3. Look at when each one starts. A font that begins downloading two seconds into the load is waiting for CSS that is waiting for something else.
  4. Repeat the test on a throttled connection. On fast broadband everything looks fine, which is why font problems reach production.

The common discovery is not that the fonts are too big; it is that there are six of them where the design uses three. Deleting the unused ones is free and takes a minute.

Preload one file, not all of them

A preload tells the browser to fetch a file immediately rather than waiting to discover it in the CSS. It is worth doing for the one font that paints the first screen — usually the body regular — and actively harmful for the rest, because every preload competes with the HTML and the CSS for the same connection.

Two details that break it: the crossorigin attribute is required even for a file on your own domain, and without it the browser downloads the font twice; and the address in the preload has to match the one in the @font-face exactly, or you get two downloads again. Both mistakes look like nothing is wrong.

The second visit should cost nothing

A font is the most cacheable thing on a site: it never changes, and when it does you give it a new name. Serving it with a long cache lifetime means a returning reader pays for it once, which is the strongest argument for hosting the files yourself — you control the header, and the file sits on the same connection as everything else.

This is also where the third-party cache myth still circulates. Browsers partition their caches per site now, so a font fetched from a public CDN on one site is downloaded again on yours: the shared-cache benefit that argument depended on has not existed for years. Self-hosting is faster, and the GDPR question disappears with it.

FamilyVariable downloadStatic download
Inter957 KB2 files9.1 MB54 files
Roboto597 KB2 files5.2 MB54 files
Lora224 KB2 files555 KB8 files
JetBrains Mono187 KB2 files892 KB16 files
The complete web font for four families, measured from the files served here. The Latin-only cut on each font page is roughly half of these.

Questions

How much should fonts weigh on a web page?
One variable family, served as WOFF2 and cut to the alphabet you actually use, typically lands between 20 and 60 KB. The same design served as full-coverage TTFs across four static weights can cost half a megabyte. The visible result is the same; the difference is entirely in how the files were prepared.
Do fonts slow down a website?
They can, in two ways: the bytes themselves, and the delay before text can be drawn. The bytes are fixed by format and subsetting. The delay is controlled by preloading the file and choosing a font-display value deliberately rather than accepting the default.
Are variable fonts better for performance?
If you use three or more weights, almost always — one variable file is usually smaller than three static ones and is a single request. If you use exactly one weight, a static file for that weight is smaller. The break-even is around two weights.
What causes layout shift when a font loads?
The fallback font and the real font measure differently, so every line re-flows at the moment of the swap. Matching the fallback more closely with size-adjust, ascent-override and descent-override removes most of it, and font-display: optional removes it entirely at the cost of sometimes not showing the font at all.
Should I preload my web fonts?
Preload the one file that paints the first screen, and no more. Every preload competes for bandwidth with the HTML and CSS. The link needs the crossorigin attribute and an address identical to the one in your @font-face, or the browser downloads the font twice.

Fonts in this post

  • Inter

    Sans-serif · Rasmus Andersson · Variable

  • Roboto

    Sans-serif · Christian Robertson, ParaType, Font Bureau · Variable

  • Lora

    Serif · Cyreal · Variable

  • JetBrains Mono

    Monospace · Philipp Nurullin, Konstantin Bulenkov · Variable

Find the font for your next project.

All 337 families here are free for commercial use, and every download carries its license inside the zip.