font preload without crossorigin
Fonts are always fetched in CORS mode; a font preload without crossorigin doesn't match that request, so the font is downloaded twice.
- Avoid
- Harmful
- Severity
- HarmfulActively breaks something for users.
- Basis
- SpecifiedThe evidence is in a current standard.
- Detectable
- YesMatched exactly. Autofixable when the rule carries a fix.
- Matches
link[rel~="preload" i][as="font" i]:not([crossorigin])Element rule, anywhere in the document.- Fix
- None — reports only
- Impacts
- Performance
- Related
link/preload-as
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2"> is the font
preload almost everyone writes first, and it does the opposite of what it’s for. The browser
downloads the font early, as asked. Then the stylesheet asks for the same font, the browser
decides the early copy doesn’t match, and downloads it again.
Why avoid
Fonts are fetched in CORS mode, always. The CSS Fonts specification’s font fetching
requirements fetch every @font-face URL with destination “font” and CORS mode “cors”,
whether the font is on another origin or on your own. Nothing about the page changes that.
A preload is only used if it matches the request that follows. The HTML Standard keys
preloaded responses on four things: the URL, the destination, the request mode and the
credentials mode. A <link rel="preload"> without crossorigin makes a no-cors request.
When the stylesheet’s cors request for the same font arrives, its key doesn’t match, so
the preloaded copy is never consumed. Chromium says as much in the console: “A preload for
‘…’ is found, but is not used because the request mode does not match. Consider taking a
look at crossorigin attribute.”
The page pays for the font twice. web.dev puts it bluntly: “Fonts preloaded without the crossorigin attribute will be fetched twice!” Tens of kilobytes of WOFF2 are downloaded early and thrown away, at high priority, competing with the critical CSS and images the preload was meant to make room for. The text still waits for the second copy.
Use instead
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
A bare crossorigin means anonymous, which matches the font’s own request. Add it even
for fonts on your own origin. MDN: the attribute “needs to be set to match the resource’s
CORS and credentials mode, even when the fetch is not cross-origin”. A cross-origin font
also needs Access-Control-Allow-Origin on its response, preload or not.
Detectability
Fully detectable. The selector matches a preload token in rel, as="font"
case-insensitively, and no crossorigin attribute at all.
crossorigin="use-credentials" mismatches too, because it sends credentials the font
request doesn’t, but this rule doesn’t catch it. There is no autofix: the fix adds an
attribute, and every fix here only removes.
Resources
- CSS Fonts Module Level 4 — font fetching requirements — fonts are fetched with destination “font” and CORS mode “cors”.
- HTML Standard — link type “preload” — preloaded responses are keyed on URL, destination, mode and credentials mode.
- Chromium —
resource_fetcher.cc,PrintPreloadMismatch— “is found, but is not used because the request mode does not match. Consider taking a look at crossorigin attribute.” - web.dev — Preload critical assets to improve loading speed — “Fonts preloaded without the crossorigin attribute will be fetched twice!”
- MDN — rel=preload: CORS-enabled fetches —
crossoriginmust match the resource’s CORS and credentials mode even for same-origin fetches.
This page is generated from content/rules/link/preload-font-crossorigin.md, the same file the linter is built from. Think the rule is wrong, or that browsers moved on? Say so — that is the most useful issue you can file.