Skip to main content

Preload Hint for Critical Web Fonts With crossorigin

Issue No: 116

Category: Resource Hints & Performance Issue Type: Warning Priority: Important


Description

Pages that use custom web fonts should declare <link rel="preload" as="font" crossorigin> tags for those fonts so the browser fetches them early and eliminates Flash of Invisible Text (FOIT) caused by fonts not being available when text first renders.

The XeoPix crawler detects web font usage by inspecting inline <style> blocks for @font-face rules and checking for <link> tags pointing to known font CDN origins (e.g., fonts.googleapis.com, fonts.gstatic.com, fonts.bunny.net, use.typekit.net). The trigger for missing font preloads only fires when the page shows evidence of web font usage.


How Do We Capture It

Where to Find

Inside HTML <head>:

<link rel="preload"
as="font"
type="font/woff2"
href="/fonts/inter-regular.woff2"
crossorigin>

The crossorigin attribute is required even for same-origin fonts when using rel="preload" for font resources.

HTML Extraction Flow

The XeoPix crawler downloads the raw HTML response and parses the <head> block:

  1. Issues an HTTP GET to the target URL.
  2. Reads raw response bytes without JavaScript execution.
  3. Scans the <head> block for all <link rel="preload"> tags.
  4. Filters for tags where the as attribute equals font.
  5. Extracts the href, type, and presence of the crossorigin attribute from each matched tag.
  6. Records all font preload hrefs and whether each declares crossorigin.
  7. Sets font_preload_has_crossorigin to FALSE if any font preload tag is missing the attribute.
  8. Scans all inline <style> blocks in the page for @font-face rules; sets has_inline_font_face = TRUE if found.
  9. Scans all <link rel="stylesheet"> tags for hrefs matching known font CDN hostnames (fonts.googleapis.com, fonts.gstatic.com, fonts.bunny.net, use.typekit.net, cloud.typography.com); sets has_known_font_cdn_link = TRUE if found.
  10. Sets has_web_font_signals = TRUE if either has_inline_font_face or has_known_font_cdn_link is TRUE.
  11. Sets has_web_fonts_but_no_preload = TRUE if has_web_font_signals = TRUE AND has_font_preload = FALSE.

Validation Logic

The crawler validates:

  • Whether any <link rel="preload" as="font"> tag exists.
  • Whether every matched font preload tag includes the crossorigin attribute.
  • Whether the href is a valid non-empty URL.
  • Whether inline <style> blocks contain @font-face rules.
  • Whether any <link> tag points to a known font CDN hostname.

How to Get It

Crawler should:

  1. Parse raw HTML <head>.
  2. Find all: link[rel="preload"][as="font"].
  3. Extract href, type, and whether crossorigin attribute is present for each.
  4. Count matched tags; flag if any are missing crossorigin.
  5. Scan all inline <style> blocks for @font-face keyword.
  6. Scan all <link rel="stylesheet"> hrefs for known font CDN hostnames.
  7. Set web font signal flags based on findings from steps 5 and 6.

What to Store

FieldTypeComment
has_font_preloadBOOLEANWhether any font preload link tag is declared in the page head
font_preload_hrefsTEXT[]Array of font href values declared in preload tags
font_preload_countINTNumber of font preload link tags found on the page
font_preload_has_crossoriginBOOLEANWhether all font preload tags include the crossorigin attribute
font_preload_missing_crossorigin_countINTNumber of font preload tags that are missing the crossorigin attribute
has_inline_font_faceBOOLEANWhether any inline style block contains an @font-face rule
has_known_font_cdn_linkBOOLEANWhether any link stylesheet points to a known font CDN hostname
has_web_font_signalsBOOLEANWhether the page shows any scriptable evidence of web font usage
has_web_fonts_but_no_preloadBOOLEANWhether web font signals exist but no font preload hint is declared

Condition for Trigger

The following trigger rules evaluate font preload presence (guarded by web font detection) and crossorigin compliance.

  • Trigger Rule 1: Web Fonts Detected But No Font Preload Declared

    • Target Field: has_web_fonts_but_no_preload
    • Evaluation Logic: = TRUE
    • Severity: WARNING
    • Diagnostic Message: "This page shows evidence of web font usage (inline @font-face or a known font CDN link) but declares no font preload hint. Without a preload hint, fonts are not discovered until CSS is fully parsed, causing Flash of Invisible Text (FOIT). Add a preload hint for each critical font file."
  • Trigger Rule 2: Font Preload Missing crossorigin Attribute

    • Target Field: font_preload_missing_crossorigin_count
    • Evaluation Logic: > 0
    • Severity: WARNING
    • Diagnostic Message: "One or more font preload tags are missing the crossorigin attribute. Without crossorigin, the browser initiates a second separate fetch for the font file, causing the preload to be wasted and FOIT to persist."

Sources


Long Description

Web fonts are one of the most common sources of Flash of Invisible Text (FOIT) — the condition where text on a page is invisible while the font is downloading. This happens because browsers wait for a font to load before rendering text that uses it.

The standard font loading path without preload:

  1. Browser downloads HTML.
  2. Browser downloads CSS (render-blocking).
  3. CSS is parsed; browser discovers @font-face rule referencing /fonts/inter.woff2.
  4. Only now does the browser request the font file.
  5. Text is invisible until the font arrives — FOIT.

With <link rel="preload" as="font" crossorigin> in <head>:

  1. Browser parses the preload tag immediately on HTML download.
  2. Font fetch begins at the highest priority, in parallel with CSS.
  3. By the time CSS is parsed and text needs to render, the font is already available.
  4. FOIT is eliminated or drastically reduced.

Why crossorigin is required:

Font resources are always fetched using anonymous CORS mode by the @font-face rule in CSS. The preload hint must match the same CORS mode as the actual fetch. Without crossorigin on the preload tag:

Preload request: same-origin mode
Actual @font-face request: CORS anonymous mode

→ Browser cannot reuse the preloaded response → second download initiated
→ Preload hint is completely wasted

Example correct font preload:

<link rel="preload"
as="font"
type="font/woff2"
href="/fonts/inter-v13-regular.woff2"
crossorigin>

Common failure scenarios:

1. Font Preload Without crossorigin

<!-- BAD: crossorigin missing -->
<link rel="preload" as="font" href="/fonts/inter.woff2">

<!-- GOOD -->
<link rel="preload" as="font" href="/fonts/inter.woff2" crossorigin>

2. Preloading the Wrong Font Format

Preloading .ttf when the browser would prefer .woff2 means the preloaded file may never be used, and the preferred format is fetched late.

3. Preloading All Fonts Instead of Critical Ones

Preloading 10 font files (all weights and styles) delays the highest-priority resources. Only preload the one or two font files used in above-the-fold text.

4. Preload Href Mismatch With @font-face src

If the preload href does not exactly match the URL in the @font-face src declaration, the browser treats them as different resources and downloads both.


How to Fix

Add <link rel="preload" as="font" crossorigin> for each critical web font file in the page <head>:

<link rel="preload" as="font" type="font/woff2" href="/fonts/inter-regular.woff2" crossorigin>
<link rel="preload" as="font" type="font/woff2" href="/fonts/inter-bold.woff2" crossorigin>

Guidelines:

  • Always include the crossorigin attribute — it is required for all font preloads regardless of origin.
  • Include the type attribute matching the font format (font/woff2, font/woff) to allow browsers that do not support the format to skip the preload.
  • Only preload fonts used in above-the-fold text — limit to 2–3 files maximum.
  • The href must exactly match the URL in the corresponding @font-face src declaration.
  • Place font preload tags early in <head>, before any <link rel="stylesheet"> tags.