Type something to search...
What Is font-display, and Which Value Should You Use?

What Is font-display, and Which Value Should You Use?

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:

  1. 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.
  2. 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.
  3. 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

ValueBlock periodSwap periodWhat readers see
autoBrowser defaultBrowser defaultIn practice the same as block in current browsers
blockShort, about 3 secondsInfiniteInvisible text for up to 3s, then fallback, then swap whenever ready
swapExtremely short, about 0–100msInfiniteFallback almost immediately, swaps whenever the font arrives
fallbackExtremely short, about 100msShort, about 3 secondsFallback quickly; swaps only if the font arrives within about 3s
optionalExtremely short, about 100msNoneUses 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.

ContentRecommended valueWhy
Body textswap or optionalReadable immediately; optional if CLS is a priority and you have a well-matched fallback
Headlines and display typeswap, preloadedBrand impact matters, and the font is usually small enough to arrive fast
Long-read articlesfallbackAvoids a late swap that moves text the reader has already started on
Logos set in a web fontblockBetter to briefly show nothing than the wrong letterforms; better still, use an SVG logo
Icon fontsblockFallback text would be meaningless; consider SVG icons instead
Secondary weights (italic, bold)swap or optionalSmall visual change, rarely worth blocking for

A Practical Default

For most sites, start with this:

  1. font-display: swap for the primary text font.
  2. Preload the one or two files used above the fold.
  3. 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-display in 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-face rules. Third-party widgets and plugins often load their own fonts with the default auto.

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:

  1. MDN Web Docs: font-display — the values and the font display timeline.
  2. W3C: CSS Fonts Module Level 4 — the specification defining block, swap, and failure periods.
  3. web.dev: Best practices for fonts — how font-display, preloading, and fallbacks affect Core Web Vitals.
  4. Next.js Docs: Font optimization — how next/font sets display values and generates fallbacks.
  5. WordPress Developer Resources: Global settings and styles (theme.json) — the theme.json typography settings including font faces.
Share :

Related Posts

Ascenders, Descenders, and Baselines: The Anatomy of a Letterform

Ascenders, Descenders, and Baselines: The Anatomy of a Letterform

You align an icon next to a button label and it looks a pixel or two too high, no matter how you adjust vertical-align. You set overflow: hidden

Continue Reading
Are Google Fonts GDPR-Compliant?

Are Google Fonts GDPR-Compliant?

In late 2022, thousands of small business owners in Germany and Austria opened letters demanding a few hundred euros in "damages" because their websi

Continue Reading
How to Audit Web Font Performance with Lighthouse?

How to Audit Web Font Performance with Lighthouse?

A client sends you a screenshot of their PageSpeed Insights report: performance score 61, LCP 3.9 seconds, and a vague list of warnings. They want to

Continue Reading