deadhead
link/preload-font-crossorigin

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

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.