font-display: optional vs swap
The font-display descriptor in @font-face decides what the browser shows while a web font downloads and what happens if the download is slow. For static sites the choice is almost always between two values. swap shows fallback text at once and switches to the web font whenever it arrives. optional gives the font a very short window and, if it misses, keeps the fallback for that page view. The first guarantees brand typography and risks layout shift; the second guarantees stability and sometimes shows the fallback.
This guide explains the timeline behind each value, measures both on a real template, and gives a rule for picking per font. It is part of Font Loading Strategies for Static Sites.
Prerequisites
- Self-hosted fonts with
@font-facerules you control. - A way to test on a slow connection: DevTools throttling or WebPageTest.
- Field data on CLS and LCP, ideally split by first and repeat visits.
The Three Periods
Every font-display value is a combination of three periods that start when the browser first needs the font:
- Block period. Text using the font is drawn invisibly. If the font arrives, it is used straight away.
- Swap period. Text is drawn in the fallback. If the font arrives, the text is re-rendered in it.
- Failure period. The fallback is used for the rest of the page's life, even if the font arrives later.
block and auto hide text for up to three seconds, which delays LCP whenever text is the largest element, so they are rarely the right choice for body text. fallback sits between the two main options. In practice the decision is between swap and optional.
What swap Costs
With swap, text is visible immediately, so LCP is never held back by the font. The cost is the re-render when the font arrives. If the fallback is a plain system font, paragraphs rewrap and change height, and every element below moves. On a long article the swap can shift the whole viewport.
Two things reduce that cost. Preloading the font makes it arrive earlier, often before first paint on fast connections, so there is nothing to swap; see Preloading Fonts Without Double Downloads. A metric-matched fallback makes the swap move nothing even when it does happen; see Metric-Matched Fallback Fonts with size-adjust. With both in place, swap shows the brand font almost every time and costs almost no CLS.
A third, less visible cost is the text re-render itself. When the font swaps, the browser repaints every text node that uses it. A later, larger paint of the same text element can also become a new LCP candidate, so a very late swap on a text-heavy hero can nudge LCP later rather than earlier, even though the reader could already read the text.
What optional Costs
With optional, the browser gives the font about 100 milliseconds from when it is first needed. If the file is already in the memory or HTTP cache, or a preload has delivered it, the font is used from the first paint. If not, the page renders in the fallback and stays that way; the download continues in the background and the font is cached for the next page.
The cost is typographic: on a first visit over a slow connection, readers see the fallback. On a multi-page static site that usually means one page, because the second page view hits the cache. The benefit is that font loading can never shift layout and never delays text.
Choosing Per Font
The decision does not have to be site-wide. Apply it per @font-face rule according to what the font does:
| Font role | Recommended value | Why |
|---|---|---|
| Body text | optional with a preload, or swap with a matched fallback | Most text on the page; stability matters most |
| Headings and hero text | swap with a matched fallback | Brand-critical, often the LCP element |
| Code blocks | optional | System monospace fonts are good; shifts in code are distracting |
| Rarely used weights and italics | swap | Small areas, small shifts, not worth a preload |
| Icon fonts | block, or replace with inline SVG | Fallback glyphs are meaningless |
If you are unsure, walk each face through three questions: is it an icon font, is it used for text above the fold on most pages, and can you give it a metric-matched fallback? The answers lead to one value.
A useful default for documentation sites is optional plus a preload for the body regular weight, and swap with metric-matched fallbacks for everything else. Marketing sites with strong brand typography often prefer swap everywhere with matched fallbacks.
Setting It in Common Generators
The descriptor lives in your CSS, so the change is the same everywhere, but font helpers sometimes set it for you:
- Astro with
@fontsourcepackages: the imported CSS usesswap. Override by writing your own@font-facerules, or by using the variable font package and a small wrapper stylesheet. - Next.js
next/font: passdisplay: 'optional'in the loader options; the default isswap. - Hugo and Eleventy: edit the
@font-facerules in your stylesheet directly. - Google Fonts CSS API: the
&display=query parameter sets it, but self-hosting is better for performance anyway.
After the change, check the built CSS: search the output directory for font-display and confirm every face has the value you intended.
Measuring the Effect
Compare variants in the field, not only in the lab. Lighthouse runs on a clean profile and, with its simulated throttling, often misses the font window that real readers hit. Log which font actually rendered with document.fonts.check('16px Inter') at the load event, send it with your web-vitals beacon, and split CLS and "font shown" by first and repeat views. That split is what shows whether optional is costing brand typography on the pages that matter.
Pitfalls & Rollback
- optional without a preload. The font rarely arrives within 100 ms on a first view; many readers will never see it on landing pages.
- Assuming optional fixes all font CLS. It fixes swap shifts, but a late-loading stylesheet that sets fonts can still move text.
- Mixing values for one family. A regular weight with
optionaland a bold withswapcan mix fonts in a paragraph; keep weights used together consistent. - Lighthouse "ensure text remains visible" audit. It passes for both
swapandoptional; do not treat it as a CLS check. - Service workers that precache fonts. A precached font is always ready within the window, so
optionalbehaves like instant loading after the first visit — good, but it hides the first-view cost from anyone testing on their own browser. - Rollback: change the descriptor back; no other code depends on it.
Conclusion
swap always ends with the web font and can shift layout; optional never shifts and occasionally keeps the fallback for one page view. Pair swap with metric-matched fallbacks, pair optional with a preload, and choose per font: stability for body and code text, brand fidelity for headings. Measure in the field, split by first and repeat views, before settling on one.
FAQ
What is the difference between font-display optional and swap?
With swap the browser shows fallback text immediately and switches to the web font whenever it arrives, however late. With optional the browser waits about 100 milliseconds; if the font is not ready by then, the page uses the fallback for the rest of that page view and the font is only cached for later.
Does font-display optional mean my font is never shown?
No. On a first visit over a slow connection the fallback may be used, but the font still downloads into the cache, so later page views and repeat visits render it immediately. On fast connections with a preload it usually arrives within the window on the first view as well.
Which font-display value is best for Core Web Vitals?
optional gives zero font-swap layout shift and never delays text, so it is the safest for CLS and LCP. swap is equally fast for LCP but can shift layout unless the fallback is metric-matched. block delays text and hurts LCP.
Should icon fonts use optional?
No. An icon font rendered in a fallback shows letters or empty boxes instead of icons. Use block for icon fonts, or better, replace them with inline SVG.
Related
- Parent: Font Loading Strategies for Static Sites — the full font policy.
- Preloading Fonts Without Double Downloads — making optional work on first views.
- Metric-Matched Fallback Fonts with size-adjust — making swap shift-free.
- Eliminating Layout Shift from Web Fonts — finding font shifts in field data.
- Largest Contentful Paint Optimization for Static Sites — why text visibility matters for LCP.