Web Performance

Precarga de fuentes: prioriza tus fuentes más importantes

Updated febrero 24, 2026
Usa <link rel=preload> para indicarle al navegador qué fuentes son las más importantes. Reduce el FOUT, mejora el LCP y entiende cuándo la precarga ayuda y cuándo no.

Font Preloading: Prioritize Your Most Important Fonts

Every network request starts with a discovery phase — the browser must first encounter a reference to a resource before it can begin downloading it. For CSS stylesheets, discovery happens when the browser parses the HTML <head>. For fonts, discovery happens later: after the stylesheet is downloaded, parsed, and the browser has built a render tree that includes text nodes requiring custom typefaces.

This cascade means fonts typically start downloading hundreds of milliseconds into the page load, long after other assets have begun transferring. Font preloading breaks this dependency chain by announcing font files to the browser as early as possible — often before the HTML <body> is even parsed.


How Font Preloading Works

The browser's preload scanner is a secondary parsing thread that runs ahead of the main HTML parser. It scans the raw HTML stream looking for high-priority resources to fetch immediately, without waiting for the full DOM to be built. By default, the preload scanner finds CSS files and images with explicit <link> and <img> tags. It does not find fonts, because fonts are referenced inside CSS files that haven't been downloaded yet.

<link rel="preload"> extends the preload scanner's reach. When you add a preload hint for a font, the browser initiates that font download immediately upon parsing the <head>, parallel to the CSS download — no cascade dependency required.

The timeline comparison illustrates the impact:

Without preload:

0ms    HTML parsing begins
50ms   CSS request initiated
350ms  CSS download complete, parsed
360ms  Font request initiated (discovered in CSS)
700ms  Font download complete
700ms  Text renders with custom font

With preload:

0ms    HTML parsing begins
50ms   CSS request initiated
50ms   Font request initiated (from preload hint in <head>)
350ms  CSS download complete
400ms  Font download complete
400ms  Text renders with custom font (300ms earlier)

The 300ms difference in this example is the elimination of the cascade delay — the time between CSS parsing and font discovery. On a real page with additional render-blocking resources, this savings can be even larger.


The Preload Syntax Explained

The <link rel="preload"> element for fonts requires three specific attributes to work correctly:

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

rel="preload"

This tells the browser to fetch the resource with high priority and cache it for later use. Resources loaded via rel="preload" count against the page's resource budget but do not block rendering — they're fetched speculatively, ready for when the page needs them.

href

The exact URL of the font file. This must match the src URL in your @font-face declaration precisely — including the subdirectory, filename, and query string if any. A mismatch means the browser downloads the font twice: once from the preload hint, and again when it encounters the @font-face rule.

as="font"

The as attribute tells the browser what type of resource is being preloaded. This determines the request priority, the Content Security Policy check that applies, and the cache behavior. Using as="font" ensures the resource is fetched with font-appropriate priority and stored in the font cache.

Without as="font", the browser may fetch the resource with a lower priority, defeating the purpose of preloading.

type="font/woff2"

The MIME type allows the browser to skip the download if it doesn't support the format. A browser that doesn't support WOFF2 (essentially none today) would skip the preload rather than downloading an unusable file. This attribute is technically optional but is a good practice for forward-compatibility.

crossorigin

This is the most counterintuitive requirement. Font requests are always made with CORS headers, even for fonts hosted on your own domain. If the crossorigin attribute is absent from the preload hint but present (implicitly) in the @font-face rule, the browser treats them as different resources and downloads the font twice.

Include crossorigin on every font preload hint, even for self-hosted fonts.


What to Preload (and What Not To)

Preloading is not universally beneficial. Preloading the wrong resources can actually hurt performance by competing with truly critical assets for bandwidth and connection slots.

What to Preload

The primary body text font, Regular weight. This is the font used to render the largest volume of text on most pages. Slow loading of this font causes the most visible FOIT or FOUT.

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

Heading font if it's visually prominent above the fold. If your H1 uses a decorative display face and it's the largest element on the page (your LCP element), preloading it directly improves LCP score.

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

Fonts used in critical UI components. Navigation labels, primary call-to-action buttons, and hero text are all strong preload candidates. If users interact with these elements before the font loads, the FOUT creates a jarring experience.

What Not to Preload

Every font weight you use. If your design uses Inter at Regular, Medium, Semibold, and Bold, preloading all four adds 60–100KB of preloaded fonts. Only the Regular weight appears above the fold; the others load fast enough via normal discovery.

Icon fonts. Icon fonts are typically loaded lazily and appear below the fold. Preloading them competes with text fonts for early bandwidth.

Fonts for below-the-fold content. If a decorative pull-quote font only appears mid-article, preloading it steals bandwidth from resources that affect the initial paint.

Fonts that aren't on the critical path. If a font loads in under 100ms anyway (due to caching or CDN proximity), preloading it provides no measurable benefit and adds a hint that the browser must process.

Preload and Conditional Fonts

Be careful with unicode-range subsetting and preloading together. If you preload inter-latin.woff2 but the page also loads inter-cyrillic.woff2 conditionally based on unicode-range, you should only preload the file that's unconditionally needed:

<!-- Preload the base Latin file — always needed for English content -->
<link rel="preload" href="/fonts/inter-latin.woff2" as="font" type="font/woff2" crossorigin>

<!-- Do NOT preload the Cyrillic file — only loaded when Cyrillic characters appear -->

Preloading and Core Web Vitals

Font preloading has a direct, measurable impact on Core Web Vitals, particularly LCP and CLS.

LCP Impact

Largest Contentful Paint measures when the largest visible content element finishes rendering. For content-heavy pages, this is frequently a heading or hero text block. If that text uses a custom font, LCP is blocked until the font loads.

Preloading the heading font eliminates this dependency. Rather than waiting for: 1. CSS to download 2. Font to be discovered in CSS 3. Font to download

The font downloads in parallel with step 1, and is ready the moment CSS finishes parsing. The result can be a 200–500ms improvement in LCP on first load — moving a score from "Needs Improvement" to "Good."

CLS Impact

Preloading also reduces Cumulative Layout Shift, but the mechanism is different. When a fallback font loads first and the custom font swaps in later, the difference in font metrics (character width, line height, ascenders, descenders) causes text blocks to reflow, generating CLS.

Preloading reduces the window during which the fallback font is displayed. If the custom font loads before the initial paint completes, there's no fallback period and no CLS from font swapping. This is the ideal outcome — the font is ready before it's needed, so no FOUT occurs at all.

For this reason, preloading works best in combination with font-display: optional (for zero CLS, at the cost of potentially not using the font on slow connections) or font-display: swap with size-adjust metric matching (to reduce CLS when swapping does occur).


Common Preloading Mistakes

Several subtle errors undermine font preloading in production.

Mismatched URLs

The most common mistake: the URL in the preload hint doesn't exactly match the URL in the @font-face src. This causes the browser to initiate two separate font downloads.

<!-- Preload hint -->
<link rel="preload" href="/fonts/Inter-Regular.woff2" as="font" type="font/woff2" crossorigin>

<!-- @font-face rule — note lowercase 'i' in 'inter' -->
<style>
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-regular.woff2') format('woff2');
}
</style>

On case-sensitive file systems (Linux servers), /fonts/Inter-Regular.woff2 and /fonts/inter-regular.woff2 are different files. Even on case-insensitive macOS, the browser treats them as different cache keys. Always copy-paste the URL from your @font-face declaration to your preload hint.

Missing crossorigin

Omitting the crossorigin attribute causes a double download every time. The preload fetch uses a no-CORS request; the @font-face fetch uses a CORS request. Different CORS modes mean different cache entries.

<!-- Wrong — missing crossorigin, will double-download -->
<link rel="preload" href="/fonts/inter-regular.woff2" as="font" type="font/woff2">

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

Preloading Too Many Fonts

The preload hint triggers an immediate, high-priority download. Preloading four font files competes with your CSS, JavaScript, hero image, and other critical-path resources. Chrome DevTools will warn you when preloaded resources are unused within a few seconds of page load — treat this warning seriously.

A practical ceiling: preload no more than two font files per page. In most cases, one is sufficient.

Preloading Variable Fonts with the Wrong Filename

Variable fonts typically use bracket notation in filenames: Inter[wght].woff2 or Inter-VariableFont_wght.woff2. Make sure your preload hint uses the exact filename:

<link rel="preload" href="/fonts/Inter[wght].woff2" as="font" type="font/woff2" crossorigin>

And your @font-face declaration must reference the same file:

@font-face {
  font-family: 'Inter';
  src: url('/fonts/Inter[wght].woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
}

Not Testing in Incognito Mode

Browser font caches persist across sessions. When testing font loading performance, always use an Incognito window to ensure you're seeing the uncached, first-visit experience — which is what most of your users will see.

Use the Network panel's "Disable cache" option alongside Incognito for the most accurate measurement of preload effectiveness.


Preloading is one of the highest-leverage, lowest-effort font performance optimizations available. A few lines of HTML can meaningfully shift your LCP score and eliminate visible font flashing on first load. Used precisely — for the one or two fonts that matter most for initial render — it pays significant dividends with minimal risk.


Preloading Google Fonts

Preloading fonts served from Google Fonts is more complex than preloading self-hosted fonts, because the actual font file URLs are dynamically generated by the Google Fonts API and change over time.

The Stable URL Problem

When you request a font from fonts.googleapis.com, the returned CSS contains fonts.gstatic.com URLs for the actual font files. These URLs include a hash that can change when Google updates a font. If you hardcode a specific gstatic URL in a preload hint, it may become invalid after a Google Fonts update — causing a duplicate download (the preloaded URL returns a 404, then the actual URL from CSS loads normally).

There are two practical approaches:

Option 1: Self-host and preload — download the font files, serve them from your own domain, and preload from your own URL. This is the most reliable and highest-performance approach.

Option 2: Preconnect instead of preload — use <link rel="preconnect"> for fonts.gstatic.com. This warms the connection without specifying the URL, so it works regardless of what URL the Google Fonts API returns:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">

Preconnect doesn't deliver the font file itself early — it just establishes the TCP/TLS connection to fonts.gstatic.com in advance. This saves 100–300ms of connection setup time without requiring you to know the specific font URL.


Preloading in Frameworks

Modern web frameworks have built-in mechanisms for font preloading that are worth understanding alongside the raw HTML approach.

Next.js

Next.js next/font handles preloading automatically. When you declare a font using the next/font/google module, Next.js generates the preload hints, downloads the font file at build time, and inlines the critical @font-face CSS — all without any manual configuration:

// app/layout.js
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  weight: ['400', '700'],
  display: 'swap',
  preload: true,  // default: true
});

export default function RootLayout({ children }) {
  return (
    <html className={inter.className}>
      <body>{children}</body>
    </html>
  );
}

Next.js generates a <link rel="preload"> in the <head> for the primary subset file, pointing to a locally hosted copy of the font. You get optimal preloading behavior with zero manual configuration.

Nuxt.js

Nuxt 3 with the @nuxtjs/google-fonts module offers similar automatic preloading:

// nuxt.config.ts
export default defineNuxtConfig({
  googleFonts: {
    families: {
      Inter: [400, 700],
    },
    display: 'swap',
    preload: true,
    download: true,  // Self-host the fonts
  }
});

Gatsby

Gatsby's gatsby-plugin-google-gtag and gatsby-plugin-webfonts plugins provide similar functionality. For manual control in Gatsby, add preload links to the gatsby-ssr.js file:

// gatsby-ssr.js
export const onRenderBody = ({ setHeadComponents }) => {
  setHeadComponents([
    <link
      key="font-inter"
      rel="preload"
      href="/fonts/inter-regular.woff2"
      as="font"
      type="font/woff2"
      crossOrigin="anonymous"
    />
  ]);
};

Measuring Preload Effectiveness

After implementing font preloading, verify it's working as expected. The key indicator is the start time of the font request in the Network panel — it should begin much earlier after preloading than before.

Before and After Comparison

Record a Network waterfall without preloading and note when the font request starts (typically 300–600ms into the page load, after CSS download completes). Then add the preload hint and re-record. The font request should now start within the first 100ms — essentially simultaneous with the CSS request.

If the font request doesn't move earlier after adding the preload hint, check for the URL mismatch problem. Use the browser's Console tab — a warning like "A preload for ... was found but is not used" indicates the preloaded URL doesn't match the font URL used by CSS.

Resource Hints Validator

Browser DevTools will show a warning in the Console panel if a preloaded resource isn't used within 3 seconds of page load. This warning is your signal that the preload hint is either misconfigured or preloading the wrong resource. Treat it as an error — an unused preload wastes bandwidth without providing any benefit.

Font Performance Playbook

Typography Terms

Try These Tools

Fonts Mentioned

Related Articles