Optimize web fonts by loading fewer necessary glyphs and styles, making text readable while files arrive and choosing a fallback that fits the final typeface. WOFF2, sensible subsetting and selective preloading address transfer and discovery; font-display and fallback metrics address rendering behavior. Measure both early text visibility and layout stability, because a fast download alone does not prevent a late font swap from moving content.
Find the delay before changing the font
A web font usually enters the loading sequence through CSS. The browser must discover the stylesheet, parse the @font-face rules and determine which face is needed for the text before it requests the font. A slow stylesheet or a chain of imports can therefore delay a small font file.
Inspect the Network panel with the font filter, then inspect the request initiator. Record which stylesheet triggered the request and whether the face is used above the fold. Check the rendered font in DevTools rather than assuming the first family in your CSS is the one displaying every character.
A page can use several fallback fonts within a single sentence if one face lacks certain glyphs. This matters for punctuation, currency symbols, names and mixed-language content. A visually acceptable Latin paragraph does not establish that a Hebrew or Korean edition has complete coverage.
Watch the page on a slow connection with an empty cache. Invisible text suggests a rendering policy problem; visible text that changes width suggests a fallback mismatch; a request that starts late suggests a discovery problem. Use the LCP guide when a large text block is the LCP element and the layout shift guide when movement is the main symptom.
Reduce the faces and glyphs you actually ship
WOFF2 is the usual starting format for modern browser delivery. Retain source font files in your build assets, but do not send several legacy formats without a supported-browser requirement. Check the font license before self-hosting, modifying or subsetting it; a font file being downloadable does not establish permission to redistribute a derivative.
Inventory families, weights and styles in use. A heading and body design may not need every available weight, italic and alternate style. Remove unused face declarations and unnecessary requests at the source rather than hiding the symptom with a cache plugin. Test bold and italic content after pruning so the browser does not unexpectedly synthesize a style you intended to supply.
Subsetting creates smaller files containing selected glyphs and the tables needed to render them. A unicode-range declaration tells the browser which code points a face covers; it does not physically remove glyphs from the file. To save transfer bytes, the referenced file must itself be a suitable subset.
This illustrative Latin subset declaration assumes that the named file exists and actually contains the advertised characters.
@font-face {
font-family: "Editorial Sans";
src: url("/fonts/editorial-sans-latin-regular.woff2") format("woff2");
font-style: normal;
font-weight: 400;
font-display: swap;
unicode-range: U+0000-00FF;
}
body {
font-family: "Editorial Sans", Arial, sans-serif;
}That range is not a complete multilingual strategy. It omits many characters used outside basic Western European text and is unsuitable as the only subset for this six-language site. Keep shaping, punctuation and required marks in your build's coverage tests. A range declaration that claims coverage absent from the file does not manufacture the missing glyphs.
Keep subset boundaries maintainable. Generating a tiny custom font for each article can save bytes on that page but sacrifice reuse between pages and complicate updates. For changing editorial content, stable language or script subsets often provide a more manageable starting point. Measure the requests actually triggered by representative pages before deciding whether more fragmentation helps.
Choose font-display as a reading policy
font-display is a descriptor inside @font-face. It controls how the browser handles text while that face is unavailable. Setting it on body does not configure an individual font face. The choice changes the balance between immediate readability, eventual use of the intended face and the possibility of a visible swap.
The values describe different periods; exact timing is browser-controlled rather than a portable stopwatch guarantee.
| Value | Practical behavior | Main trade-off |
|---|---|---|
auto |
Browser chooses the display policy | Less explicit control over initial text behavior |
block |
A short block period, then an unlimited swap period | Text may initially be invisible |
swap |
An extremely short block period, then an unlimited swap period | Readability arrives early, but a late swap can move text |
fallback |
An extremely short block period and a short swap period | The intended face may not replace fallback after the window |
optional |
An extremely short block period with no swap period | The visit may remain in the fallback face |
swap is useful when the intended face should eventually appear, but it does not automatically solve CLS. A fallback with different advances or line metrics can change wrapping and move everything below a paragraph. optional can avoid a late replacement, but the design must remain acceptable in the system fallback.
A decorative wordmark and a long article body may justify different decisions. Do not make body text unreadable to protect a branding preference. Test the actual content and devices your design supports. A declaration that behaves well with a cached font can still produce a distracting first visit.
Use the font-display reference when selecting the behavior. Then test with both font requests blocked and normal delivery so that the fallback is a designed state rather than an accidental one.
Preload only a genuinely critical face
Preload can bring a font request forward before normal CSS discovery would trigger it. It also uses bandwidth early, when HTML, CSS and the LCP image may be competing for resources. Loading every weight and language subset with preload defeats much of the browser's demand-driven font selection.
This example preloads one face used in the initial viewport and declares exactly the same URL in CSS.
<link rel="preload"
href="/fonts/editorial-sans-latin-regular.woff2"
as="font" type="font/woff2" crossorigin>
<style>
@font-face {
font-family: "Editorial Sans";
src: url("/fonts/editorial-sans-latin-regular.woff2") format("woff2");
font-style: normal;
font-weight: 400;
font-display: swap;
}
</style>Font preloads need the appropriate CORS mode, including for self-hosted font requests. For cross-origin hosting, the response must also permit the request. Match URL, resource type and request mode so the browser can reuse the preload instead of making a second request.
Preload is not a CSS declaration: it does not apply the font by itself. Confirm that the face is actually used soon after loading and that the Console is not reporting an unused preload. Compare the request waterfall before and after adding the hint. A font that starts sooner but delays a more important image may be a poor trade.
For a third-party font service, inspect the stylesheet and font origins separately. A selective preconnect can reduce connection setup to a critical origin, but it cannot remove the stylesheet discovery step or guarantee a faster outcome. Do not preconnect to every external domain on the page.
Match fallback metrics instead of accepting the jump
A fallback can look broadly similar yet occupy a different amount of space. Compare character widths, x-height, ascenders, descenders and line gaps. Text wrapping often matters more than a small visual difference in letterforms because an extra line changes the position of the rest of the page.
size-adjust scales glyph outlines and metrics for a face. The ascent-override, descent-override and line-gap-override descriptors can align vertical metrics. Values must be derived for the actual target and fallback pair; there is no universal percentage that fits every typeface or operating system.
This example is a syntax demonstration with illustrative values, not a calibrated match for a real “Editorial Sans” font. Replace the values after measuring your actual fonts.
@font-face {
font-family: "Editorial Fallback";
src: local("Arial");
size-adjust: 100%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
.article-body {
font-family: "Editorial Sans", "Editorial Fallback", sans-serif;
line-height: 1.6;
}The local fallback must exist on the device for that face to be available. Keep a generic family at the end of the stack and test systems where the named local font is absent. Metric overrides can reduce mismatch but do not guarantee identical line breaks for every string.
Use headings, long navigation labels, numbers, punctuation and paragraphs when comparing. Test translated text rather than duplicating an English sample in every layout. Explicit line-height can make vertical rhythm more predictable, but it does not prevent wrapping changes caused by different glyph widths.
Compare variable fonts with the styles you need
A variable font can represent a range of weights or other axes in one file. That can replace several static files, but it does not mean one variable file is always smaller than the one or two static styles a site actually uses. Compare the delivered subsets and required axes, not the marketing description of the format.
This declaration exposes a weight axis from 100 to 900, assuming the referenced font supports that range.
@font-face {
font-family: "Editorial Variable";
src: url("/fonts/editorial-variable-latin.woff2") format("woff2");
font-style: normal;
font-weight: 100 900;
font-display: swap;
}
h1 { font-family: "Editorial Variable", sans-serif; font-weight: 650; }Do not declare axis ranges the file does not contain. Check italic support separately and preserve the font's documented usage. If your build tools subset axes, verify the result visually and functionally; an unexpectedly removed axis can silently change the design.
Plan Korean, Hebrew and system fallbacks deliberately
Korean requires a broader glyph strategy than a Latin-only interface. A single comprehensive CJK asset can be expensive, while aggressive per-page subsetting risks missing dynamic text, names or newly published content. Consider stable subsets, a service's documented segmentation or a tested system stack. Verify actual requests on Korean pages, including mixed Latin abbreviations and numbers.
Hebrew needs the relevant Hebrew characters, punctuation and any marks your content supports, alongside Latin glyphs for technical terms. Font choice does not set document direction. Keep the page's RTL handling and bidirectional text behavior separate from the font-loading configuration, and test code labels, numbers and punctuation in context.
Self-hosting gives control over URLs, cache policy and update timing. A service may handle format delivery and segmentation, but introduces its own stylesheet and origins. Neither approach is automatically fastest for every page. Compare the real dependency chain, operational responsibility and privacy requirements of the chosen setup.
System fonts are a valid final design choice. They avoid a custom font transfer and can render promptly, although appearance and metrics vary by platform. Choose a stack that looks intentional on your supported systems and test every script. Removing the custom download is useful only if readability, hierarchy and character coverage remain sound.
Verify one typography change across real page states
Start with a page where fonts affect the initial viewport. Record the font requests, when readable text appears and whether headings or paragraphs move. Repeat with a cold cache, a warm cache and font delivery blocked. Include at least one Korean page and one Hebrew page if those editions are part of the site.
After changing faces, subsets or preload hints, check for duplicate downloads, missing glyphs and unexpected synthetic weights. Review the performance trace and visible layout together. A smaller font file is an intermediate result; readable, stable text is the behavior you are trying to improve.
Record the chosen font files and display policy in the performance checklist. If discovery remains late, continue with render-blocking resource analysis. Keep the resulting test in your page speed optimization workflow so a future design change does not quietly restore unnecessary faces or an unstable fallback.