Articles

font-display Explained: Controlling How Web Fonts Load

The CSS font-display property controls whether text waits for a web font or renders in a fallback first. Here's how swap, block, and optional differ.

Takina Takina · · 4 min read
Rows of metal letterpress type

font-display is a CSS property, set inside an @font-face rule, that tells the browser what to do with text while a custom web font is still downloading: hide it, show a fallback font immediately, or something in between. It’s a small property with an outsized effect on perceived load speed, because text is usually the first thing a page has to render.

Why this is a problem at all

Web fonts are files, and files take time to download. Browsers historically dealt with this in one of two unhelpful ways: the “flash of invisible text” (FOIT), where text is invisible until the font arrives, or the “flash of unstyled text” (FOUT), where a fallback font shows first and then gets swapped, sometimes causing layout shift. font-display lets you choose which behavior — or a hybrid of both — you actually want, instead of being at the mercy of the browser’s default.

The four values

@font-face {
  font-family: "Inter";
  src: url("/fonts/inter.woff2") format("woff2");
  font-display: swap;
}
  • auto — the browser’s default behavior, which varies and is generally worth overriding explicitly rather than relying on.
  • block — gives the font a short “block period” (browsers typically use around 3 seconds) where text is invisible, then falls back if the font hasn’t loaded, swapping in the real font later if it arrives. Prioritizes visual consistency over having something readable on screen quickly — usually the wrong tradeoff for body text.
  • swap — effectively no block period. The fallback font renders immediately, and the real font swaps in whenever it finishes loading, however late. This is the most common choice: text is readable the whole time, at the cost of a visible font swap.
  • optional — gives the font a very short block period, and if it hasn’t loaded by then, the browser may not swap it in at all for that page view, prioritizing avoiding layout shift and extra network use over ever showing the exact intended font on a slow connection.

There’s also fallback, a middle ground between block and optional: a short block period, then a fallback, with a limited swap window afterward — the browser gives up on swapping sooner than swap does.

How this connects to Core Web Vitals

The choice directly affects two metrics covered in our Core Web Vitals guide. block risks delaying Largest Contentful Paint if the LCP element is text, since nothing paints until the block period ends or the font loads. swap, on the other hand, can cause Cumulative Layout Shift when the fallback and web fonts have different metrics (different x-heights, character widths), so the swap visibly reflows the layout. Neither value is free of tradeoffs — font-display picks which failure mode you’re willing to accept, not a way to avoid both.

Reducing the swap’s visual impact

Two techniques mitigate layout shift without changing font-display itself:

  1. size-adjust, ascent-override, and related descriptors on a fallback @font-face declaration let you tune a system font’s metrics to more closely match the web font’s, shrinking the visible jump when the swap happens.
  2. Preloading the font file with <link rel="preload" as="font" crossorigin> — see our guide to resource hints — gets the browser fetching the font earlier in the page load, shortening how long text spends in a fallback font regardless of which font-display value you use.

A practical default

For most body text, swap combined with a preload hint for the primary font weight is the pragmatic choice: readable text immediately, and a shorter window before the swap because the font request starts sooner. Reserve optional for decorative or non-critical fonts (badges, headings far below the fold) where showing the exact typeface is nice-to-have but not worth any layout risk. Fluid type sizing, covered in our guide to clamp() and fluid typography, is a separate concern from font-display but often gets tuned alongside it, since both affect how text looks during the earliest paint.

font-display values compared

ValueInvisible text periodWhen it swapsBest for
block~3s (typical)After block period, if font arrivesRarely the right choice for body text
swapNoneWhenever the font finishes loadingBody text, primary content
fallbackShortOnly within a short window after thatA compromise for secondary text
optionalShortMay skip the swap entirelyDecorative or non-critical type

Variable fonts and icon fonts need the same treatment

font-display applies per @font-face declaration, which matters if a page loads several font files — regular weight, bold, italic, an icon font — each as its own declaration. It’s easy to set font-display thoughtfully on the primary body text font and forget that a separately-declared icon font or bold weight is still using the browser default. A page can end up with a well-tuned primary font and a jarring, unaddressed flash from a secondary one, simply because the property wasn’t set consistently across every @font-face rule in use.

Variable fonts, which pack multiple weights and styles into a single file, sidestep part of this problem by reducing the number of separate font files a page has to load in the first place — fewer @font-face declarations means fewer places font-display needs to be set deliberately rather than left to default.

The takeaway

font-display decides what happens to text while a web font is still downloading, and every value trades some combination of invisible text, layout shift, and typographic fidelity. swap is the safest general default because it keeps text readable throughout, and pairing it with a preload hint for your primary font shortens the window where the fallback is visible. Treat the property as a deliberate choice tied to your critical rendering path, not a setting to leave on whatever a starter template picked.

Takina Takina · · 5 min read

CSS will-change Explained: Compositing and Performance

The CSS will-change property hints the browser to prepare an element for an upcoming change, moving it to its own compositor layer. When to use it and when not to.

#CSS #Web Development #Performance
Takina Takina · · 4 min read

CSS Scroll-Driven Animations Explained

CSS scroll-driven animations tie keyframes to scroll position instead of a clock, running smoothly off the main thread. Here's how the timeline model works.

#CSS #Web Development #Frontend