Fonts are subject to a cross-origin rule that images and scripts are not. Serve one from a different hostname without the right header and the browser downloads it, refuses to use it, and falls back - so the file is 200 in the network panel and the console explains it in a message nobody reads.
The message
Access to font at 'https://cdn.example.com/f/inter.woff2' from origin
'https://yourdomain.com' has been blocked by CORS policy
The header
# nginx, on the host SERVING the font
location ~* \.(woff2?|ttf|otf|eot)$ {
add_header Access-Control-Allow-Origin "https://yourdomain.com";
add_header Cache-Control "public, max-age=31536000, immutable";
}
# apache / litespeed
<FilesMatch "\.(woff2?|ttf|otf|eot)$">
Header set Access-Control-Allow-Origin "https://yourdomain.com"
</FilesMatch>
crossorigin on the preload, if you preload
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
Without crossorigin on that tag the font is downloaded TWICE - once by the preload and again by the stylesheet, because they are treated as different requests. The page is slower than it would have been with no preload at all.
The simpler answer
Serve fonts from your own domain. Same origin means no CORS question, no extra DNS lookup, no second TLS handshake, and one fewer third party in the page. With HTTP/2 there is no longer any speed argument for a font CDN.
# download once, commit them, serve from /fonts/
@font-face {
font-family: "Inter";
src: url("/fonts/inter.woff2") format("woff2");
font-display: swap;
}
font-display: swap shows the fallback immediately and swaps when the font arrives. Without it the text is invisible for up to three seconds on a slow connection.