font-display is a descriptor inside a @font-face rule that controls what the browser
paints between asking for a font file and receiving it. It takes five values: auto, block,
swap, fallback and optional. They differ on two questions: how long the text stays
invisible while the browser waits, and whether the browser is still willing to switch to the
web font once it finally arrives. The descriptor does not make a font download faster. It
decides what the visitor sees during the download.
The default is a blocking period, not “show the fallback”
Left unset, browsers hide the text rather than draw it in a fallback typeface. web.dev states the length: “By default, Chromium-based and Firefox browsers block text rendering for up to 3 seconds if the associated web font has not loaded.”
Lighthouse has an audit for exactly this, and its description names the symptom: “Fonts are often large files with slow load times. Some browsers hide text until the font loads, causing a flash of invisible text (FOIT).”
The cost lands on FCP, because a page with no visible text has not painted content. web.dev puts that connection directly: “If a web font has not loaded, browsers typically delay text rendering. In many situations, this delays First Contentful Paint (FCP).”
The five values
| Value | Text while waiting | Font swapped in when it arrives |
|---|---|---|
auto | browser default, in practice a block period | yes |
block | invisible for a short block period | yes |
swap | fallback typeface immediately | yes |
fallback | fallback after a very short block | only within a short window |
optional | fallback after a very short block | no, the font is left for the next visit |
Two of them cover almost every real decision. swap says the words matter more than the
typography, which is the right answer for body text. optional says the typography is
decoration, and it is the only value that protects the layout completely, because the browser
either has the font in time or never applies it on that view.
What we can see, and on which platforms
Our proxy reads a page’s markup and adds a display setting where the declaration is in the
HTML: a Google Fonts stylesheet link with no display= parameter, or an @font-face inside an
inline <style>. Share of audited sites carrying such a declaration with no display setting,
snapshot of 2026-08-04:
| Platform | Sites | Font declared in the HTML with no display setting |
|---|---|---|
| Duda | 51 | 45 |
| WooCommerce | 57 | 18 |
| Elementor | 30 | 6 |
| WordPress | 64 | 10 |
| Bitrix | 28 | 2 |
| Webflow | 34 | 0 |
| Wix | 32 | 0 |
| Squarespace | 38 | 0 |
The three zeros are a limit of the measurement and not a clean bill of health. Those platforms declare their fonts in external stylesheets, which this pass does not rewrite, so we see no declaration rather than a correct one. Read the table as “of the declarations visible in the HTML”, which is also all a browser extension or a quick view-source will tell you. Tilda is absent for a different reason: it runs a different filter set, where fonts are inlined instead.
The context those figures sit in is in our study of web fonts across 452 audited sites: 436 of them load at least one font file, five files at the median.
What swap costs
swap removes invisible text by introducing a visible change of typeface, and if the fallback
has different metrics from the web font, the text reflows when the swap happens. Line lengths
change, everything below moves, and that is CLS. The fix is not to go back
to blocking. It is to make the fallback match: size-adjust, ascent-override and
descent-override on a local fallback @font-face bring the substitute close enough that the
swap stops moving the page.
This trade is real enough that our own filter declares it. font-display: swap is recorded in
our pipeline as improving FCP and as a possible cost to CLS, and both halves show up in
measurement.
In code
@font-face {
font-family: "Inter";
src: url("/fonts/inter.woff2") format("woff2");
font-display: swap;
}
For a Google Fonts stylesheet the same setting is a URL parameter:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter&display=swap">
What WebSpeed does with it
Two narrow edits, both in the HTML. A Google Fonts stylesheet link with no display= gets
&display=swap appended, and an @font-face block in an inline <style> gets
font-display: swap added. Fonts declared in an external stylesheet are outside this pass,
which is why the table above is a floor: on the platforms that keep their @font-face rules in
a separate file, the setting is the site’s own to make.