Web fonts on 26 homepages: 936 @font-face rules, 165 with no font-display
font-display decides what a browser shows while a web font downloads, and 165 of the 936 @font-face rules we found across 26 homepages do not declare it. Six sites use Google Fonts, and one preconnects to it. Every number is recomputed from the saved CSS.

FIELD TEST · 2026-09-20 · 26 homepages · 936 @font-face rules · one pass
Sample and method: the same 30-domain panel this series has used since 2026-08-15, one request per homepage on 2026-09-20 with a desktop Chrome user agent, no JavaScript. We then fetched the stylesheets each homepage links to and parsed every @font-face block. Every number below is recomputed from the saved HTML and CSS, not typed by hand.
A font-display value decides what a browser shows while a web font is still downloading. Across 26 homepages we found 936 @font-face rules, and 165 of them — 17.6 percent — declare no font-display at all. Fourteen of the 23 sites that ship web fonts have at least one such rule. The setting is one line, and about one in six of these rules leaves it to the browser default.
How we measured
We fetched each homepage once, saved the delivered HTML, then collected every rel="stylesheet" link and every inline <style> block, fetched up to 30 stylesheets per site, and walked each @font-face block for a font-display declaration and a list of src URLs. A rule counts as declaring the property only if the descriptor is present inside that block; a site-wide font-display elsewhere in the CSS does not count for a block that lacks it.
curl -s -L --compressed \
-A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" \
https://example.com/ -o page.html
python3 -c "
import re, urllib.request
html = open('page.html').read()
css = ''
for href in re.findall(r'<link[^>]+stylesheet[^>]+href=[\"\']([^\"\']+)', html):
if href.startswith('http'):
try: css += urllib.request.urlopen(href, timeout=20).read().decode('utf-8','replace')
except Exception: pass
faces = re.findall(r'@font-face\s*\{[^}]*\}', css, re.S)
with_display = [f for f in faces if re.search(r'font-display\s*:', f, re.I)]
print(len(faces), 'faces,', len(with_display), 'with font-display')
"
Two things this method cannot see, and both cut the same way. It reads stylesheets the page links to or inlines, so a font declared inside a script-injected stylesheet is invisible to it — one site on the panel preloads a font file but shows zero @font-face rules, which is a sign of exactly that. And it counts declarations, not rendering: a rule that declares font-display can still be overridden later in the cascade.
The 26 homepages, by @font-face rules
The distribution is uneven. One page builder generates 378 of the 936 rules on its own, three sites ship no web font at all, and the rest sit between 3 and 113. The table is the whole panel, sorted by rule count.
| Site | Faces | Display | Missing |
|---|---|---|---|
| framer.com | 378 | 248 | 130 |
| discord.com | 113 | 112 | 1 |
| arstechnica.com | 95 | 92 | 3 |
| railway.com | 45 | 45 | 0 |
| wired.com | 37 | 37 | 0 |
| bbc.com | 35 | 31 | 4 |
| notion.com | 35 | 35 | 0 |
| ycombinator.com | 29 | 28 | 1 |
| slack.com | 26 | 17 | 9 |
| supabase.com | 24 | 21 | 3 |
| theverge.com | 23 | 19 | 4 |
| substack.com | 22 | 22 | 0 |
| mozilla.org | 10 | 8 | 2 |
| techcrunch.com | 10 | 10 | 0 |
| nextjs.org | 8 | 7 | 1 |
| vercel.com | 8 | 7 | 1 |
| shopify.com | 8 | 8 | 0 |
| github.com | 7 | 5 | 2 |
| netlify.com | 7 | 7 | 0 |
| cloudflare.com | 6 | 6 | 0 |
| figma.com | 4 | 2 | 2 |
| stripe.com | 3 | 3 | 0 |
| webflow.com | 3 | 1 | 2 |
| linear.app | 0 | 0 | 0 |
| reddit.com | 0 | 0 | 0 |
| wikipedia.org | 0 | 0 | 0 |
The three zeros are not broken pages. They are pages that use the system font stack, which costs nothing to download and never flashes — the same choice the render-blocking CSS survey found in a different resource. The interesting row is slack.com: 26 rules, 9 of them without the descriptor, on a page whose whole first impression is text.
What font-display value sites actually declare
Among the 771 rules that do declare the property, one value dominates. swap is the common choice, and the values that trade visible text for stability are rare.
| Value | Rules | Effect while loading |
|---|---|---|
| swap | 612 | Fallback text shows, then swaps |
| fallback | 114 | Very short block, then swaps |
| block | 43 | Text stays invisible during the block period |
| optional | 2 | No swap; the font is skipped if slow |
| not declared | 165 | Whatever the browser's default is |
MDN defines the five values by two periods: the block period, when text that uses the font is rendered invisibly, and the swap period, when it is rendered in a fallback and then swapped. swap gives an extremely small block period and an infinite swap period, so text is never invisible for long. block gives a short block period and an infinite swap period, which is the value that produces the classic flash of invisible text.
font-display is the one line that decides whether a slow font costs you invisible text or a visible reflow.
Where the fonts come from, and who preconnects
Self-hosting is the default on this panel. Of the 1,069 font source URLs we resolved, 427 point at the site's own domain, and most of the rest point at a platform CDN the site is built on. Google Fonts appears on six sites, and only one of those six preconnects to it.
| Origin | URLs | Notes |
|---|---|---|
| Site's own domain | 427 | Self-hosted font files |
| framerusercontent.com | 308 | Framer's own CDN |
| fonts.gstatic.com | 108 | Google Fonts file host |
| website-files.com | 108 | Webflow's CDN |
| bbci.co.uk | 30 | BBC's font CDN |
| substackcdn.com | 10 | Substack's CDN |
| Inline data URI | 7 | Font embedded in the CSS |
| fonts.googleapis.com | 6 | Google Fonts stylesheet host |
The preconnect count is the part worth pausing on. Six of the 26 sites pull font CSS from Google Fonts, which is a third-party origin the browser must open a connection to, and five of them do not tell the browser to open it early. The one that does — railway.com — is also the only site whose Google Fonts links carry display=swap, which is why all 45 of its rules declare the descriptor. Google's own font guidance recommends preconnecting to a third-party font origin; on this panel it is the exception.
What this means for your own page
The useful move is not to add a value everywhere. It is to find the rules that render text you care about and make sure each one has an answer.
- List every
@font-facerule with the command above and mark the ones with nofont-display. Those are the rules running on the browser default. - Add
font-display: swapto any rule whose text a visitor reads before the font arrives. It is the value that keeps text visible, and it is what most of this panel chose. - If you load font CSS from a third-party origin, add a
preconnectto it in the head. Six sites here use Google Fonts and one preconnects; that is free time left on the table. - Do not preload every font file. Only 11 of 26 sites preload a font, and a preload that competes with your main image for bandwidth can cost more than it saves.
- Decide
font-displayper rule, based on whether the text is content or decoration. - Do not leave it to the default on a rule that renders your first heading. The default is not "no effect"; it is a choice you did not make.
One caveat runs through all of this. We counted what the CSS declares, not what a browser did with it. We did not render these pages, so we cannot tell you which ones actually flashed invisible text. If your own page renders a first heading in a web font, the check is local and takes a minute: throttle the network and reload. A crawler accessibility check answers the adjacent question of what a non-rendering client receives at all.
Common questions
How did you measure this?
One request per homepage on 2026-09-20 with a desktop Chrome user agent, no JavaScript, redirects followed, response saved as bytes. We then fetched the stylesheets each page links to, up to 30 per site, parsed every @font-face block, and recorded whether a font-display descriptor was present in that block. The panel is the same 30 domains used across this series; medium.com, stackoverflow.com, canva.com and nytimes.com returned 403 to our client and are excluded, which leaves 26.
Is font-display a ranking factor?
No, and nothing here says it is. It changes what a reader sees while a font loads, which is a Core Web Vitals question at most, and we did not measure any ranking effect. The defensible claim is narrower: it decides between invisible text and a visible swap.
Does the missing descriptor mean the text is invisible?
Not necessarily. With no font-display, the browser applies its default, and MDN lists the initial value as auto, which lets the user agent choose. Some browsers behave like block and some like swap. The point is that you did not choose, and the outcome depends on the reader's browser.
Should I self-host my fonts?
The performance case is less clear than it sounds. Google's font guidance notes that a self-hosted font removes a third-party connection, but also cites the Web Almanac finding that sites using third-party fonts rendered faster in practice. What we can add is a count: on this panel, self-hosting is the norm, and the six sites on Google Fonts mostly skip the one step that would make it cheaper.
Why does one site have 378 rules?
Because it is a page builder. Framer emits a separate @font-face block per weight, style and character subset, so a single family can become dozens of rules. That is not a problem on its own; it is why a raw rule count should not be read as a quality score.
What did you not measure?
Rendering, and anything injected by JavaScript after load. We did not measure how fast any font arrived, how much any font weighed, or whether a page shifted when it swapped. This article is about what the CSS declares, nothing more.


