Type something to search...
What is FOUT and FOIT and how do you prevent them?

What is FOUT and FOIT and how do you prevent them?

FOUT (flash of unstyled text) is when a page first shows text in a fallback font and then switches to the web font once it has downloaded. FOIT (flash of invisible text) is when the browser hides text entirely while the web font loads, leaving blank space until the font arrives or a timeout passes. Both happen because web fonts download after the page has started rendering, and the browser has to decide what to show in the meantime. FOIT is generally the worse problem because content is unreadable, so the usual approach is to accept a controlled FOUT and then make it as subtle as possible. You prevent the harsh versions of both with font-display, preloading, smaller font files and fallback fonts whose metrics match the web font.

These flashes are some of the most visible signs of a slow site. A blank headline on a slow mobile connection, or paragraphs that jump as the font swaps, make a page feel broken even when everything else is fast. In this article you'll learn what causes each flash, how browsers decide between them, how to reproduce them on purpose, and the techniques that reduce or remove them, from one line of CSS to the CSS Font Loading API.

Why the Flashes Happen

When the browser renders a page, it needs a font for every piece of text. If the CSS says to use a web font that hasn't downloaded yet, the browser has three choices:

  1. Wait: Keep the text invisible until the font arrives. This is FOIT.
  2. Show a fallback: Draw the text in the next available font in the font-family list and swap later. This is FOUT.
  3. Show a fallback and never swap: Use the fallback for the rest of the page view if the font is late.

Web fonts can't be ready instantly on a first visit because they're discovered late. The browser first needs the HTML and CSS, then has to match styles to elements before it knows which font files are needed. Only then does the download begin.

How Browsers Behave by Default

Without any instruction from you, current browsers follow the auto behaviour of the font-display descriptor, which in practice is a block strategy:

  • Block period of about three seconds: Text using the web font is invisible.
  • Fallback after the timeout: If the font still hasn't arrived, the browser shows the fallback.
  • Swap when the font arrives: Even after the timeout, the browser replaces the fallback with the web font once it loads.

On a fast connection the font often arrives well within the block period and you never notice. On a slow or congested network, visitors can stare at a page with images and layout but no words for several seconds, followed by a sudden swap. That's both flashes in one page load.

FOUT Versus FOIT Compared

FOITFOUT
What the visitor seesBlank space where text should beText in a fallback font, then a change
Content readable while loadingNoYes
Typical causeDefault or block font-displayswap or fallback font-display
Main riskSlow perceived load, poor LCPLayout shift, distracting restyle
Usually preferableOnly for icon fontsFor body and heading text

FOIT is sometimes defended as looking more polished, but a hidden headline is worse than one shown briefly in Georgia. Readers can start reading during a FOUT; they can't read invisible text.

Reproducing the Flashes

You can't fix what you can't see. Most developers have fast connections and warm caches, so the flashes never appear locally. To see them:

  1. Open DevTools and tick Disable cache in the Network panel.
  2. Choose a throttling profile such as Slow 4G, or create a custom profile with high latency.
  3. Reload and watch the text.

For a stronger effect, right-click a font request in the Network panel and choose Block request URL. The page will then show exactly what visitors see when a font fails to load, which is the fallback for the entire page view.

The Performance panel's screenshots strip is also useful. Record a page load and step through the frames to see when text appears and when it changes.

Preventing FOIT

FOIT is the easier problem to solve, because a single descriptor changes the browser's behaviour.

Set font-display

Add font-display: swap to each @font-face rule for text fonts:

@font-face {
  font-family: "Literata";
  src: url("/fonts/literata-latin-var.woff2") format("woff2");
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}

With swap, the block period is extremely short, so the fallback text appears almost immediately. If you use Google Fonts, add &display=swap to the stylesheet URL to get the same effect.

Other values let you trade between the two flashes. fallback gives the font a short window to arrive before committing to the fallback, and optional uses the web font only if it's available almost immediately. Each value is explained in the guide to the font-display property.

Keep Block Behaviour for Icon Fonts

If you still use an icon font, invisible is better than wrong. A fallback font would render icon code points as random letters or empty boxes, so keep font-display: block for icon fonts, or better still, switch to inline SVG icons.

Making FOUT Less Noticeable

Once text is visible during loading, the remaining problem is the swap itself. A good FOUT is short and doesn't move anything.

Load the Font Sooner

The less time the fallback is on screen, the less noticeable the change. Preload the most important font so the download starts as soon as the browser reads the head:

<link
  rel="preload"
  href="/fonts/literata-latin-var.woff2"
  as="font"
  type="font/woff2"
  crossorigin
>

Serving fonts from your own domain, subsetting them and using WOFF2 all shorten the download too.

Choose a Similar Fallback

The jarring part of a FOUT is usually a change in width and height, not the change in letterforms. Pick a fallback with similar proportions. A wide sans-serif web font falls back better to Verdana than to Arial Narrow, and a serif text face usually falls back best to Georgia.

Match the Fallback's Metrics

You can go further by creating a tuned fallback @font-face that points to a local font and adjusts its size and vertical metrics:

@font-face {
  font-family: "Literata Fallback";
  src: local("Georgia");
  size-adjust: 98%;
  ascent-override: 92%;
  descent-override: 24%;
  line-gap-override: 0%;
}

body {
  font-family: "Literata", "Literata Fallback", Georgia, serif;
}

The numbers above are placeholders. The right values come from the two fonts' metrics, and tools such as Fontaine, Capsize and Next.js's next/font calculate them for you. The technique is covered fully in the guide to preventing layout shift from web fonts.

Controlling Loading With JavaScript

The CSS Font Loading API gives you finer control when CSS alone isn't enough. It's supported in all current browsers.

Grouping Repaints

When a page uses several font files, each one can swap in separately, causing a series of small reflows. You can load them together and apply the web fonts in one step by toggling a class:

body {
  font-family: Georgia, serif;
}

.fonts-loaded body {
  font-family: "Literata", Georgia, serif;
}
const fonts = [
  '400 1em "Literata"',
  'italic 400 1em "Literata"',
  '700 1em "Literata"',
];

Promise.all(fonts.map((font) => document.fonts.load(font)))
  .then(() => {
    document.documentElement.classList.add("fonts-loaded");
    try {
      sessionStorage.setItem("fontsLoaded", "1");
    } catch {
      // Storage unavailable; the class still applies for this page view.
    }
  })
  .catch(() => {
    // Fonts failed to load; the fallback stays in place.
  });

The @font-face rules still need to exist in your CSS. document.fonts.load() triggers the download of matching faces and resolves when they're ready.

Skipping the Flash on Repeat Views

On later pages in the same session the fonts are usually in the HTTP cache already. You can add the class immediately with a tiny inline script in the head, so returning visitors see no swap at all:

<script>
  try {
    if (sessionStorage.getItem("fontsLoaded")) {
      document.documentElement.classList.add("fonts-loaded");
    }
  } catch (e) {}
</script>

Two-Stage Loading

A refinement sometimes called FOFT, flash of faux text, loads only the regular weight first. The browser can synthesise bold and italic from it briefly, and the real bold and italic files load in a second stage. This gets the most important file on screen quickly, at the cost of a brief moment of synthetic styles. It's worth considering for long-form sites with several styles but is overkill for most.

Checking Status in the Console

To see which faces have loaded on a page, run this in the console:

for (const face of document.fonts) {
  console.log(face.family, face.weight, face.style, face.status);
}
Literata 200 900 normal loaded
Literata 200 900 italic unloaded

An unloaded status means no element on the page has needed that face yet, which is normal for unused styles.

Which Strategy Should You Use?

  • Most content sites: font-display: swap, one preloaded font, and a metric-matched fallback. Simple and effective.
  • Sites that must never shift: font-display: optional with a preload. First-time visitors on slow connections may see the fallback, but there's no swap.
  • Sites with several font files: Add the class-based Font Loading API approach so all fonts swap together.
  • Performance-critical pages: Consider a system font stack, which has no flash of any kind.

FAQ: FOUT and FOIT

A brief FOUT is usually acceptable and much better than invisible text, because people can start reading immediately. It becomes a problem when the swap causes text to reflow, so match your fallback's size to the web font.

With the default behaviour, current browsers hide text for up to about three seconds before showing a fallback. If the font arrives during that time, it's used straight away.

No, it does the opposite. It removes FOIT by showing the fallback immediately, which means you get a FOUT instead. You then reduce the impact of the FOUT with preloading and fallback metric overrides.

Flash of faux text. It's a two-stage loading technique where the regular weight loads first and the browser briefly synthesises bold and italic from it, until the real files arrive.

Mostly on first visits. Once fonts are cached, browsers can usually render with them straight away. Uncached visits, slow networks and missing cache headers make the flashes more common.

Yes, by using a system font stack, or by using font-display: optional so the web font is only used when it's available almost instantly. Both mean some visitors won't see your custom font on the first page view.


Conclusion

FOUT and FOIT are two sides of the same problem: web fonts arrive after the browser is ready to draw text. FOIT hides text and leaves readers waiting, while FOUT shows a fallback and swaps it later. Because readable content matters most, the standard approach is to remove FOIT with font-display: swap and then make the resulting FOUT short and stable.

Preload the main font, keep files small, choose a fallback with similar proportions, and override its metrics so the swap doesn't move anything. Use the CSS Font Loading API if you need to group several fonts into a single change. With those pieces in place, most visitors won't notice the font loading at all.

Share :

Related Posts

How to make typography accessible?

How to make typography accessible?

You make typography accessible by choosing clear typefaces, setting text in relative units so it scales with user preferences, giving it enough colou

Dive Deeper
What are the parts of a letterform?

What are the parts of a letterform?

A letterform is the shape of a single letter, and typographers break it down into named parts. The main ones are the stem (the main vertical

Dive Deeper
What are ascenders, descenders and the baseline?

What are ascenders, descenders and the baseline?

The baseline is the invisible line that letters sit on. Ascenders are the parts of lowercase letters that rise above the x-height, such as th

Dive Deeper