
What is FOUT and FOIT and how do you prevent them?
- Sajjad
- Typography
- 11 Oct, 2026
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:
- Wait: Keep the text invisible until the font arrives. This is FOIT.
- Show a fallback: Draw the text in the next available font in the
font-familylist and swap later. This is FOUT. - 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
| FOIT | FOUT | |
|---|---|---|
| What the visitor sees | Blank space where text should be | Text in a fallback font, then a change |
| Content readable while loading | No | Yes |
| Typical cause | Default or block font-display | swap or fallback font-display |
| Main risk | Slow perceived load, poor LCP | Layout shift, distracting restyle |
| Usually preferable | Only for icon fonts | For 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:
- Open DevTools and tick Disable cache in the Network panel.
- Choose a throttling profile such as Slow 4G, or create a custom profile with high latency.
- 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: optionalwith 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.


