How to Eliminate FOIT with Font Subsetting and Swap
Flash of Invisible Text (FOIT) degrades user experience and hurts
Core Web Vitals by hiding text behind empty space while custom web fonts
load. Combining font subsetting with the CSS
font-display: swap property provides an effective,
two-pronged strategy to eliminate this problem entirely. Subsetting
strips out unneeded glyphs to drastically reduce file sizes and
accelerate delivery, while font-display: swap tells the
browser to immediately display fallback text until the custom font is
ready. Together, these techniques ensure that page content remains
instantly readable on any connection.
Understanding FOIT
When a browser encounters an external web font declared in CSS, it often delays rendering the affected text until the font file finishes downloading. By default, browsers like Chrome, Firefox, and Safari hold text in an invisible state for up to three seconds. If the network is slow or the font file is large, users are left staring at blank spaces where headlines and body copy should be. This behavior is Flash of Invisible Text.
How
font-display: swap Solves the Visibility Problem
The font-display descriptor in the
@font-face rule controls how a font is rendered relative to
its download progress. Applying the swap value eliminates
the initial block period where text is invisible.
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom-font.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}When set to swap, the browser:
- Gives the font face a zero-second block period, meaning text is never hidden.
- Instantly renders the text using the next available fallback font in
the font stack (e.g.,
Arial,system-ui). - Downloads the custom font in the background.
- Swaps the fallback font with the custom font as soon as the file finishes loading.
This approach converts FOIT into FOUT (Flash of Unstyled Text). While the user may notice a slight visual shift when the font changes, they can read the content immediately, preventing frustration and lowering bounce rates.
How Font Subsetting Minimizes the Swap Duration
While font-display: swap ensures content is readable
right away, a noticeable jump between the fallback font and the custom
font can be visually jarring and potentially trigger Cumulative Layout
Shift (CLS). This is where font subsetting becomes critical.
Standard font files often contain thousands of characters, including multiple language scripts, ligatures, historical symbols, and mathematical glyphs that a website will never use. A full font file can easily exceed 200KB.
Font subsetting is the process of generating a custom, trimmed font file containing only the characters required for your content (for instance, basic Latin characters, numbers, and standard punctuation).
Subsetting reduces font payloads by:
- Drastically shrinking file sizes: A 150KB font can
often be reduced to 15KB–30KB using tools like Glyphhanger, Subfont, or
Google Fonts'
textquery parameter. - Accelerating download times: Smaller files transit the network significantly faster, particularly on mobile connections.
- Shortening the swap delay: Because the file arrives almost immediately, the transition from fallback font to custom font occurs within milliseconds, often before the user even registers the swap.
You can also use the CSS unicode-range descriptor
alongside subset files to ensure the browser only downloads the specific
character sets requested by the page:
@font-face {
font-family: 'CustomFont';
src: url('/fonts/custom-font-latin.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
}The Combined Result
Relying solely on font-display: swap prevents invisible
text, but slow-loading full-weight fonts can create an unpleasant and
prolonged FOUT. Relying solely on font subsetting makes fonts load
faster, but network hiccups can still trigger the default multi-second
invisible block.
By uniting both methods, font-display: swap guarantees
that text is visible without delay, while font subsetting ensures the
custom typography arrives so quickly that the swap is nearly
imperceptible.