Anticode Open builder

Google Fonts performance: loading web fonts fast and without layout shift

Web fonts cost time in two ways: the files have to arrive before text can render in the right face, and when the face swaps in, lines can reflow and push the page around. Good Google Fonts performance comes down to loading fewer files, telling the browser early where they live, and choosing what happens while they're on the way.

Updated · By the Anticode team

What actually happens when a page loads a font

A browser doesn't know it needs a font until it has the HTML, has fetched the stylesheet that declares the @font-face, and has found text on the page that uses it. With Google Fonts that's a chain across two hosts: the page asks fonts.googleapis.com for a small CSS file, and that CSS points at the font files on fonts.gstatic.com. Each new host means a DNS lookup, a connection and a TLS handshake before the first byte arrives.

While that's happening, the browser has to decide what to show. It can hide the text for a short period (a flash of invisible text) or draw it in a fallback face and swap later (a flash of unstyled text). Neither is free: invisible text delays reading, and a swap can change line lengths enough to move everything below it, which shows up as Cumulative Layout Shift.

The five fixes, in order of payoff

  1. Load fewer files. Every weight and style is a separate download unless you use a variable font, where one file covers a whole weight range. Two or three static weights of one family is plenty for most sites; a regular, an italic and three weights of two families can easily be ten files.
  2. Set font-display. With Google Fonts, add &display=swap to the CSS URL. swap shows the fallback immediately and swaps when the font arrives. optional gives the font a very short window and otherwise keeps the fallback for that page view, which avoids late shifts at the cost of sometimes not showing your face on a first visit.
  3. Preconnect to the font host. A <link rel="preconnect"> to fonts.gstatic.com (with the crossorigin attribute, because fonts are fetched in CORS mode) lets the connection start before the CSS asks for it.
  4. Subset. Google Fonts already splits files by unicode-range, so a page in English only downloads the Latin subset. If you self-host, do the same: shipping Cyrillic, Greek and Vietnamese glyphs to readers who will never see them is pure waste.
  5. Match the fallback. The size-adjust, ascent-override and descent-override descriptors let you tune a local fallback such as Arial to take up nearly the same space as your web font, so the swap barely moves anything.

Self-hosting Google Fonts: when it helps

Self-hosting Google Fonts means downloading the WOFF2 files (the licences of the families on Google Fonts allow it) and serving them from your own domain. The old argument for using Google's servers was a shared cache: a visitor might already have the file from another site. Modern browsers partition their caches by site, so that benefit has gone.

Google's servers compared with self-hosting
Google Fonts CSS APISelf-hosted
Extra connectionsTwo hosts to reachNone; same origin as the page
Subsetting and formatDone for you, per browserYour job, with a tool such as a font subsetter
Updates to the familyPicked up automaticallyManual
Third-party requestThe visitor's IP address reaches GoogleNo third party involved

If a site already self-hosts its other assets and someone will maintain the files, self-hosting is usually a little faster and simpler for privacy reviews. Otherwise the hosted API with display=swap and a preconnect is fine for most small sites. Either way, the number of files matters more than where they come from.

Mistakes that cost the most

  • Loading every weight "just in case". Ticking 100 to 900 in the Google Fonts picker can mean nine files, most of them never used.
  • Two display faces for one headline style. A second family for headings doubles the requests; if it's only used at one size, consider whether weight and size alone can do the job, as font pairing for websites discusses.
  • font-display: block on body text. Visitors on slow connections stare at a blank page for up to three seconds.
  • Preloading everything. A preload competes with images and CSS for bandwidth. Preload one or two files that the first screen really needs.

Accessibility and fonts

Performance and accessibility meet in a couple of places. Text should never be shipped as an image to get a particular face: WCAG's criterion on images of text asks for real text where the same visual presentation is possible. And the fallback that shows while a font loads is what some readers see for the whole visit on a poor connection, so pick one with similar width and a legible x-height rather than whatever the browser defaults to.

How Anticode handles fonts

Each of Anticode's seven design systems uses exactly one family (Geist, IBM Plex Sans, Jost, Fredoka, Archivo, Figtree or Inter Tight), and the Critic's lint and the design gate both flag a page that loads more than one family or one pairing. That rule exists for design reasons, but it also keeps the font budget small. In the design engine's pages, the family is requested from Google Fonts as a single variable weight range with display=swap and a preconnect, so one family doesn't turn into one file per weight.

App builds run in a sandbox with no network access, and Google Fonts is the one outside resource they're allowed to load. That means an app can have a real typeface without opening the door to other third-party requests.

Questions people ask

Does Google Fonts slow down a website?

A little, mostly through the extra connections and the number of files. One family with a preconnect and display=swap adds very little; five weights of three families add a lot.

Is font-display: swap always the right choice?

It's the safe default for body text. If layout shift matters more than showing the face on a first visit, optional is worth trying, ideally with a matched fallback.

Are variable fonts always smaller?

Not always. One variable file is usually smaller than four or more static weights, but larger than a single static weight. Count what you actually use.

Sources

  1. font-display, MDN Web Docs, checked
  2. size-adjust, MDN Web Docs, checked
  3. Understanding Success Criterion 1.4.5: Images of Text, W3C, checked