Web Font Performance: Cut Load Time With Fonts
Fonts are the forgotten performance problem. While images, JavaScript and CSS are optimized regularly, web fonts often slip through unnoticed -- even though, according to HTTP Archive, they are loaded on roughly 68 percent (HTTP Archive Web Almanac, 2024) of all pages and account for several font files per page at the median. A single unsubsetted font file in TTF format can weigh 200 to 400 KB (project experience), and because text without a loaded font stays invisible in many browsers at first (Flash of Invisible Text, FOIT), fonts directly delay what the user perceives as load time. On top of that comes layout shift: when the browser swaps the fallback font for the web font, the text jumps -- a classic CLS culprit. This article shows how to systematically reduce font-related load time and layout shift with font-display, preload, subsetting, WOFF2 and matched fallback metrics -- without changing the design.
Why Web Fonts Slow Down Performance
A web font is an external resource that the browser has to load, decode and apply to text before it can display the final typography. Unlike an image, the font does not block a single container but potentially the entire visible text content -- precisely the part of the page most often responsible for the Largest Contentful Paint (LCP). If the LCP element is a block of text, the LCP score depends directly on when the font becomes available.
The default browser behavior makes the problem worse. Without explicit control, many browsers use a block period of up to three seconds for web fonts (Source: Google web.dev, 2024): as long as the font is not loaded, the text stays invisible. Only afterwards -- if the font is still missing -- is the fallback font shown. This behavior is called Flash of Invisible Text (FOIT) and is the worst option for the user, because content would be visible but is deliberately withheld.
The second variant is the Flash of Unstyled Text (FOUT): the browser shows the fallback font immediately and swaps it as soon as the web font has loaded. Content is readable early, but the swap shifts text if the font metrics differ -- which harms CLS. The art of web font optimization is to avoid FOIT and to make the FOUT jump so small that it is barely noticeable. Both mechanisms explain why fonts play a bigger role in the Core Web Vitals and in perceived frontend performance than their file size would suggest.
FOIT - invisible text
The browser withholds text for up to three seconds (Google web.dev) while the font loads. Content exists but is deliberately hidden.
FOUT - jumping text
Fallback first, then a swap to the web font. Different metrics shift the text and create layout shift (CLS).
Third-party requests
External font CDNs add DNS resolution and a connection setup - an avoidable roundtrip on the critical path.
Large files
Unsubsetted TTF/OTF files with all glyphs and languages can reach 200 to 400 KB (project experience) per style.
Too many styles
Regular, bold, italic, light: each style is a separate file. Four styles can quickly mean over 500 KB of font data.
LCP dependency
If the LCP element is a text block, the LCP score depends directly on when the font is available - the font becomes the bottleneck.
font-display: Avoid FOIT, Control the Swap
The single most important lever is the CSS descriptor font-display inside the @font-face rule. It controls how the browser behaves during a font's loading phase and distinguishes three periods: a block period (text invisible), a swap period (fallback visible, swap allowed) and a failure period (fallback stays). The chosen strategy determines the length of these periods.
font-display: swap sets the block period to nearly zero. The browser shows the fallback font immediately and swaps it as soon as the web font has loaded. This eliminates FOIT and keeps text readable from the start -- the price is a potential FOUT jump. swap is the right choice for most body text, because readability matters more than a perfectly stable font transition.
font-display: optional goes one step further: it grants the font only a very short window of around 100 milliseconds (Source: Google web.dev, 2024). If the font does not load in time, the fallback font stays permanently -- and no later swap occurs. This fully eliminates the font-swap layout shift (CLS contribution effectively zero) and is ideal for pages where stability matters more than exact brand typography. On a repeat visit the font is usually in the cache and is used immediately.
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap; /* avoid FOIT, text readable instantly */
src: url('/fonts/inter-regular.woff2') format('woff2');
unicode-range: U+0000-00FF; /* subset: load Latin glyphs only */
}
/* Match the fallback font to the web font to minimize CLS */
@font-face {
font-family: 'Inter Fallback';
src: local('Arial');
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
body {
font-family: 'Inter', 'Inter Fallback', system-ui, sans-serif;
}Practical recommendation
font-display: swap for body text that must be readable immediately, and font-display: optional for headlines or brand fonts where a stable layout matters more than a reliable font swap on the first visit. This avoids FOIT and keeps the fonts' contribution to CLS low.WOFF2 and Subsetting: Drastically Reduce Font Data
The font format has a direct impact on data volume. WOFF2 is the modern web font format and uses a Brotli compression tuned for fonts. Compared to uncompressed TTF/OTF, WOFF2 reduces file size to about 30 percent (Google web.dev, 2024) -- a 300 KB TTF file becomes around 90 KB. WOFF2 is supported by all current browsers (Source: MDN Web Docs, 2024); an additional WOFF fallback is unnecessary in most projects today.
The lever is even larger with subsetting. A complete font file often contains thousands of glyphs for dozens of languages, symbols and rare special characters. A German-language website typically needs only the Latin letters, umlauts, digits and common punctuation. Subsetting removes all unneeded glyphs, which can reduce file size by a further up to 70 percent (project experience). Tools like fonttools/pyftsubset (open source) or the unicode-range descriptor in @font-face make it possible to deliver only the character ranges that are actually used.
Subsetting can also be split by language: using several @font-face rules with different unicode-range, the browser loads only the subsets needed for the text actually displayed. A page with Latin text only then requests no Cyrillic or Greek glyphs. This technique is particularly effective for multilingual shops and is part of our approach in frontend optimization.
| Format / method | Relative size | Browser support | Recommendation |
|---|---|---|---|
| TTF / OTF (uncompressed) | ~100 % | Universal, but large | Avoid for the web |
| WOFF | ~60 % | All older browsers | Emergency fallback only |
| WOFF2 | ~30 % (Google web.dev) | All current browsers (MDN) | Standard format for the web |
| WOFF2 + subset | often under 25 % (project experience) | All current browsers | Optimal for single-language sites |
| Variable font (WOFF2) | 1 file instead of many styles | Modern browsers (MDN) | Efficient with multiple weights |
Preload and Self-Hosting: Shorten the Critical Path
Even the smallest font file is of little use if the browser discovers it late. By default, the browser only finds a font once it has parsed the CSS and determined that a visible element uses that font -- which is late in the loading process. With in the HTML head, the critical font is requested early and with high priority, before the CSS is fully processed.
<head>
<!-- Load the critical font early and prioritized -->
<link rel="preload"
href="/fonts/inter-regular.woff2"
as="font"
type="font/woff2"
crossorigin>
<!-- Stylesheet as usual -->
<link rel="stylesheet" href="/styles.css">
</head>Use preload with care
crossorigin attribute is mandatory for fonts, otherwise the browser downloads the file twice.A second decisive lever is self-hosting. When fonts are loaded via an external CDN, an additional DNS resolution and a connection setup to a third host are incurred -- an avoidable roundtrip on the critical path. If the fonts are instead served from your own server under the same domain, that third-party connection is eliminated, the font benefits from an already open HTTP/2 or HTTP/3 connection, and from the fast server response time of your own infrastructure.
Beyond performance, self-hosting has a legal advantage: loading fonts via external services transmits visitors' IP addresses to third parties. A German regional court classified this practice in 2022 as a violation of the GDPR and awarded damages to a plaintiff (Source: LG Munich I, judgment 3 O 17493/20, 2022). Hosting fonts locally is therefore both a privacy and a performance measure -- a point we review in the technical analysis of every website.
Drive Layout Shift From Font Swaps to Zero
Cumulative Layout Shift (CLS) is one of the three Core Web Vitals; Google rates a value below 0.1 (Google web.dev, 2024) as good. A considerable share of unexpected layout shifts comes from the font swap: when the fallback font is narrower, wider, taller or shorter than the web font, the swap shifts the surrounding text and all elements below it. On a long text page a single font swap can trigger several small shifts.
The solution is matched fallback metrics. With the CSS descriptors size-adjust, ascent-override, descent-override and line-gap-override, a local fallback font (such as Arial or a system font) can be adjusted to occupy nearly the same space as the web font. size-adjust scales glyph width and height, while the override descriptors adjust the vertical metrics. If the fallback font is precisely matched to the web font, the later swap barely registers -- the font swap's contribution to CLS approaches zero.
The right override values can be measured or computed automatically with open-source tools. The fontaine project, for example, generates matched fallback @font-face rules automatically at build time; some frameworks already have this optimization built in. To determine the values manually, compare the units-per-em, ascent and advance widths of the web font and fallback and derive the override percentages. This technique combines ideally with optimizing interaction responsiveness (INP), because stable layouts also improve reflow behavior during interactions.
The three levers with the biggest impact
Variable Fonts: Many Styles in One File
Classic font families consist of separate files per style: regular, bold, italic, light and so on. If a page loads four of these styles, that is four HTTP requests and quickly over 500 KB of font data (project experience). Variable fonts solve this by encoding an entire weight spectrum -- and sometimes width and style -- in a single file. The CSS axis font-weight can then address any intermediate value without loading further files.
Whether a variable font is more efficient depends on the actual use. If many weights and styles are genuinely used, the single variable file saves requests and often total volume compared to several static styles. If only a single weight is needed, a static, subsetted WOFF2 is usually smaller, because the variable font carries interpolation data for all axes. The decision should therefore be based on a realistic needs analysis -- a typical part of our performance work on Shopware shops and other systems.
Variable fonts can also be subsetted and delivered in WOFF2 format. When using a variable font, additionally check which axes are really needed: by limiting the axis ranges (for example only font-weight 400 to 700 instead of 100 to 900), you can save volume here too. Combined with font-display and preload, the optimization logic stays the same as for static fonts.
Implementation in Shopware and CMS Systems
In practice, inefficient fonts often come from themes and plugins that embed external font CDNs or deliver complete font families with all languages. For a Shopware shop based on the open-source edition, fonts can be controlled via the theme build system: the font files are stored locally, embedded in the theme SCSS via @font-face with font-display and unicode-range, and the critical font is requested via a preload hint in the storefront template.
For classic CMS and page builders, the most common lever is to disable external font embeds and replace them with locally hosted, subsetted WOFF2 files. Many themes offer settings for this or can be adapted via a child theme. After the switch it is important to carefully verify that all characters used -- including umlauts, quotation marks and special characters -- are contained in the subset, so that no replacement glyphs or tofu boxes appear.
- Replace external font CDNs with locally hosted WOFF2 files (performance + GDPR)
- Subset fonts to the needed character ranges (unicode-range, pyftsubset)
- Set font-display: swap for body text, optional for headlines/brand fonts
- Preload only the critical above-the-fold font with crossorigin
- Match fallback metrics with size-adjust and overrides to reduce CLS
- Reduce the number of styles or evaluate a subsetted variable font
- After the switch, visually check umlauts, special characters and all languages
Measurement: Make Font Performance Visible
Whether the optimization works can be measured. In Chrome DevTools the Network panel shows which font files are loaded, how large they are and when they arrive. Filtering for font resources reveals unsubsetted giant files and external third-party requests at a glance. The Performance panel marks layout shift events and shows whether a font swap moves the text.
At the metric level the optimization shows up in several values: First Contentful Paint drops because text appears earlier thanks to font-display: swap; LCP improves when the LCP element is a text block; and CLS falls once the font swap is neutralized by matched fallbacks. Common performance measurement tools flag render-blocking and inefficient fonts in dedicated audits, and the field data in Google Search Console shows the real trend over time.
It is important to combine lab and field data. A synthetic lab measurement shows behavior under defined conditions, but only real user data (field) shows how fonts behave across different devices, networks and cache states. Continuous performance monitoring surfaces regressions -- for example when a theme update re-embeds an external font or a new font weight is added unsubsetted.
Fonts are the part of performance most often overlooked - and at the same time one of the few where a single CSS line like font-display noticeably improves the perceived page build-up.
Web font optimization is rarely an isolated project. It ties into frontend optimization, into Core Web Vitals work and into the server configuration. It is precisely this holistic view -- from the font file via the critical path to layout stability -- that makes the difference between a marginal and a noticeable improvement in load time. If you would like your project analyzed, start via our services or directly via contact.