
What Is font-display, and Which Value Should You Use?
- Sajjad
- Typography
- 01 Oct, 2026
Open a site on a slow train connection and you may stare at a page full of layout with no words in it — buttons, images, empty spaces where the headline should be. Three seconds later the text appears all at once. Or the opposite happens: the text shows up instantly in Arial, and a moment later every line jumps as the brand font replaces it. Both behaviors come from one CSS descriptor that most developers set once by copying it from a Google Fonts URL and never think about again.
That descriptor is font-display. This article explains the font loading timeline it controls, exactly what each of its five values does, how it interacts with preloading and caching, and which value to choose for body text, headings, logos, and icon fonts.
What Is font-display?
font-display is a descriptor inside an @font-face rule that tells the browser how to render text while a web font is downloading, and what to do if the download is slow. It does not make the font load faster. It decides what readers see in the meantime.
@font-face {
font-family: "Inter";
src: url("/fonts/inter-latin.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
Because it is a descriptor, it belongs inside @font-face, not on an element. You cannot write body { font-display: swap }. For hosted services, the value is set through the service: Google Fonts uses the display URL parameter, for example &display=swap.
The Font Loading Timeline
Every web font goes through up to three periods, starting when the browser first needs the font to render some text:
- Block period. If the font has not loaded, the browser renders the text with an invisible fallback. Space is reserved, but nothing is visible. If the font arrives during this period, it is used immediately.
- Swap period. If the font still has not loaded, the browser renders the text with a visible fallback font. If the web font arrives during this period, the browser swaps it in.
- Failure period. If the font has not loaded by the end of the swap period, the browser gives up and keeps the fallback for the life of the page.
Invisible text during the block period is called a flash of invisible text (FOIT). The visible fallback being replaced is a flash of unstyled text (FOUT). The values of font-display simply set how long each period lasts. For a closer look at the two flashes and how to soften them, see our guide on FOUT vs. FOIT.
The Five Values
| Value | Block period | Swap period | What readers see |
|---|---|---|---|
auto | Browser default | Browser default | In practice the same as block in current browsers |
block | Short, about 3 seconds | Infinite | Invisible text for up to 3s, then fallback, then swap whenever ready |
swap | Extremely short, about 0–100ms | Infinite | Fallback almost immediately, swaps whenever the font arrives |
fallback | Extremely short, about 100ms | Short, about 3 seconds | Fallback quickly; swaps only if the font arrives within about 3s |
optional | Extremely short, about 100ms | None | Uses the font only if it is available almost immediately; otherwise fallback for the whole page view |
The exact timings are recommendations in the CSS Fonts specification, and browsers follow them closely: the "short" block period is 3 seconds and the "extremely short" block is 100ms or less.
block
Text stays invisible for up to three seconds. On a fast connection you never notice. On a slow one, readers see a blank page with images and backgrounds but no words. Reserve block for cases where showing the wrong font is worse than showing nothing, such as an icon font, where the fallback would render ligature names like "shopping_cart" as plain text.
swap
Text renders in the fallback almost immediately and swaps to the web font whenever it arrives, even if that takes ten seconds. This is the most popular value and what Google Fonts and next/font use by default. It guarantees readable text early, which helps First Contentful Paint and Largest Contentful Paint when the LCP element is text. The cost is a visible font swap that can cause Cumulative Layout Shift if the fallback's metrics differ from the web font's.
fallback
A compromise. Text shows in the fallback after about 100ms, and the web font replaces it only if it arrives within roughly three seconds. On a very slow connection the reader keeps the fallback, so they never get a late, jarring swap in the middle of reading.
optional
The font is used only if it is available within about 100ms, typically because it is cached or preloaded and arrives fast. Otherwise the browser uses the fallback for the entire page view while the font still downloads in the background and goes into the cache. The next page view then uses the web font from cache. This gives you zero font-related layout shift on the current page, at the cost of first-time visitors on slow networks never seeing your font on their first page.
Which Value Should You Use?
There is no single right answer, but there are good defaults by content type.
| Content | Recommended value | Why |
|---|---|---|
| Body text | swap or optional | Readable immediately; optional if CLS is a priority and you have a well-matched fallback |
| Headlines and display type | swap, preloaded | Brand impact matters, and the font is usually small enough to arrive fast |
| Long-read articles | fallback | Avoids a late swap that moves text the reader has already started on |
| Logos set in a web font | block | Better to briefly show nothing than the wrong letterforms; better still, use an SVG logo |
| Icon fonts | block | Fallback text would be meaningless; consider SVG icons instead |
| Secondary weights (italic, bold) | swap or optional | Small visual change, rarely worth blocking for |
A Practical Default
For most sites, start with this:
font-display: swapfor the primary text font.- Preload the one or two files used above the fold.
- Define a metric-adjusted fallback so the swap does not shift layout.
That combination shows text immediately, gets the real font in quickly, and keeps the swap visually quiet.
When optional Is the Better Choice
Choose optional when Core Web Vitals scores are a hard requirement, when your fallback stack is already attractive (a well-tuned system font stack is a strong fallback), or when most traffic is repeat visitors who will have the font cached. Pair it with a preload so first-time visitors on decent connections still get the font within the 100ms window.
How font-display Interacts with Preload
Preloading starts the font download early, during HTML parsing, instead of waiting until the browser has built the render tree and discovered which fonts are needed. That makes it far more likely the font arrives during the block period.
<link
rel="preload"
href="/fonts/inter-latin.woff2"
as="font"
type="font/woff2"
crossorigin
/>
With optional, Chromium goes further: if a font with optional is preloaded, the browser may briefly delay the first render (up to the 100ms block period) so the font can be used on the very first paint, eliminating both the swap and the layout shift. Our guide to preloading web fonts covers the details and the common mistakes.
Reducing the Cost of swap
The biggest downside of swap is layout shift when the fallback and the web font have different widths and vertical metrics. You can neutralize most of it with metric override descriptors on a fallback @font-face:
@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;
}
The exact percentages depend on the font pair. Tools such as Fontaine and the fallback generation in next/font calculate them for you.
Setting font-display in Common Tools
Google Fonts
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400..700&display=swap"
rel="stylesheet"
/>
Change display=swap to display=optional or display=fallback as needed.
Next.js with next/font
import { Inter } from "next/font/google";
const inter = Inter({
subsets: ["latin"],
display: "swap", // the default; "optional" and others are accepted
variable: "--font-inter",
});
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" className={inter.variable}>
<body>{children}</body>
</html>
);
}
next/font also generates a size-adjusted fallback font automatically, which addresses the layout shift problem described above.
WordPress theme.json
In a block theme, each font face in theme.json accepts a fontDisplay key:
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 3,
"settings": {
"typography": {
"fontFamilies": [
{
"name": "Inter",
"slug": "inter",
"fontFamily": "Inter, sans-serif",
"fontFace": [
{
"fontFamily": "Inter",
"fontWeight": "100 900",
"fontStyle": "normal",
"fontDisplay": "swap",
"src": ["file:./assets/fonts/inter-latin.woff2"]
}
]
}
]
}
}
}
WordPress outputs the matching @font-face rule with the descriptor included.
Checking What Your Site Actually Uses
- In Chrome DevTools, open the Network panel, filter by Font, and throttle to "Slow 4G" to watch the swap behavior.
- Lighthouse flags fonts without a non-blocking
font-displayin its font display check (long known as "Ensure text remains visible during webfont load"). Our walkthrough on auditing web font performance with Lighthouse shows where to find it. - Search your CSS bundle for
@font-facerules. Third-party widgets and plugins often load their own fonts with the defaultauto.
font-display FAQ
The default is auto, which lets the browser decide. Current browsers treat auto like block, hiding text for up to about three seconds while the font loads. That is why explicitly setting a value is recommended.
Not always. Swap gives the fastest visible text, which helps First Contentful Paint, but the later font swap can cause layout shift. Optional avoids layout shift entirely but may skip your font on first visits. Swap with a metric-matched fallback is the most balanced choice for most sites.
No. It is a descriptor of the @font-face rule, so it only works inside @font-face blocks. For hosted fonts, use the provider's option, such as the display parameter in Google Fonts URLs.
On the first page view it may not be used if it takes longer than about 100ms. The browser still downloads and caches it, so later page views use it. Preloading the font makes it much more likely to be used on the first view too.
Use block, because the fallback text for icon fonts is meaningless or confusing. A better long-term solution is to switch to inline SVG icons, which render immediately and do not depend on font loading.
Barely. A cached font is usually available within the block period, so it renders immediately regardless of the value. The descriptor matters most on first visits and slow connections.
Conclusion
font-display is one line of CSS, but it decides whether readers on slow connections see blank space, a fallback font, or a jarring swap. The values map neatly onto trade-offs: block hides text to protect appearance, swap shows text immediately and swaps later, fallback limits how late a swap can happen, and optional refuses to swap at all.
For most sites, swap plus preloading the critical file plus a metric-adjusted fallback gives the best balance. Move to optional when layout stability is the priority, and keep block for the rare cases where the wrong glyph is worse than no glyph. Whatever you choose, set it explicitly rather than leaving it to auto.
Here are some useful references for going deeper on font-display:
- MDN Web Docs: font-display — the values and the font display timeline.
- W3C: CSS Fonts Module Level 4 — the specification defining block, swap, and failure periods.
- web.dev: Best practices for fonts — how font-display, preloading, and fallbacks affect Core Web Vitals.
- Next.js Docs: Font optimization — how
next/fontsets display values and generates fallbacks. - WordPress Developer Resources: Global settings and styles (theme.json) — the theme.json typography settings including font faces.


