Lazy loading web fonts means delaying the download of font files until they're actually needed typically when the browser encounters text that uses those specific fonts. Instead of forcing every visitor to download all your fonts upfront (which blocks rendering), you tell the browser to load them strategically. This reduces initial page load time, cuts render-blocking requests, and improves metrics like Largest Contentful Paint (LCP) and First Contentful Paint (FCP).
What's the difference between lazy loading fonts and using font-display?
These are related but not the same thing. font-display is a CSS property that controls how text behaves while a font is downloading. Setting font-display: swap, for example, shows fallback text immediately and swaps in the web font once it arrives. It does not delay the font request itself the browser still starts downloading the font as soon as it sees the CSS.
True lazy loading means preventing the browser from requesting the font file at all during initial page load. The font only gets fetched when a specific condition is met, like scrolling to a section that uses it. You can learn more about combining these approaches in our lazy loading web fonts CSS technique tutorial for deeper implementation details.
Why does lazy loading web fonts improve performance?
Every font file your page requests adds to the critical rendering path. If you're loading five font weights and two families, that could easily be 300–500 KB of font data the browser must process before it can paint text. On slower connections, this creates a noticeable delay.
Lazy loading fixes this by splitting font delivery into tiers. The fonts visible above the fold load immediately. Fonts used in lower sections, in modals, or on hover states only download when triggered. This directly helps with Core Web Vitals you can read our analysis of the fastest loading web fonts for Core Web Vitals to see how font size and loading strategy affect real-world scores.
How do you lazy load web fonts with CSS alone?
The cleanest CSS-only approach uses the font-display property combined with @font-face declarations and media queries. Here's a practical pattern:
Step 1: Define your critical fonts with font-display swap
Fonts used in the hero section or above-the-fold content should load immediately but not block rendering:
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-var.woff2') format('woff2');
font-display: swap;
font-weight: 400 700;
}
Step 2: Lazy load secondary fonts with media query trick
This technique loads additional fonts only when the browser needs them by wrapping @font-face inside a media query that resolves to true after initial rendering:
@media (min-width: 1px) {
@font-face {
font-family: 'Playfair Display';
src: url('/fonts/playfair-display.woff2') format('woff2');
font-display: swap;
font-weight: 400;
}
}
The min-width: 1px media query always evaluates to true, but browsers treat @font-face inside media queries as non-critical and lower their download priority. The font won't block rendering and gets fetched after more important resources.
Step 3: Use the Intersection Observer for on-demand loading
For truly deferred fonts (loaded only when a user scrolls to a section), combine CSS with a small JavaScript snippet that adds a class when an element enters the viewport:
/ CSS font family only applies when class is present /
.gallery-title {
font-family: system-ui, sans-serif;
}
.fonts-loaded .gallery-title {
font-family: 'Cormorant Garamond', serif;
}
// JavaScript observe when gallery section appears
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
document.documentElement.classList.add('fonts-loaded');
observer.disconnect();
}
});
observer.observe(document.querySelector('.gallery'));
This way, Cormorant Garamond only downloads when the user scrolls near the gallery section. It's genuinely lazy loaded.
Which fonts are good candidates for lazy loading?
Any font that isn't needed during the initial screen render is a candidate. Common examples include:
- Decorative display fonts used in section headings further down the page
- Italic or bold weights that only appear in blog post body text
- Icon fonts loaded via CSS that represent interactive elements below the fold
- Fonts used in modals, dropdown menus, or tooltips that appear on user interaction
- Alternative language subsets like Cyrillic or Greek that only apply to specific visitors
Fonts that should not be lazy loaded include the primary body text font and any font used in your above-the-fold heading. These are critical fonts and should use <link rel="preload"> in the document head instead. Choosing the right lightweight Google Fonts for mobile also helps reduce the payload of fonts you do load early.
How does the preload trick work for critical fonts?
For fonts you need immediately (but still want optimized), add a preload hint in your HTML <head>:
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>
This tells the browser to fetch the font early in the page load, before the CSS is parsed. Paired with font-display: swap in your @font-face, you get the best of both worlds: early download without render blocking.
The combination of preloading critical fonts and lazy loading secondary fonts is the approach most performance-focused developers use. Make sure your critical fonts are in WOFF2 format for the best compression in modern browsers.
What are the most common mistakes when lazy loading fonts?
- Lazy loading your primary body font. This causes a visible flash of unstyled text (FOUT) that users notice immediately. Your main text font should always be preloaded or loaded in the
<head>. - Not providing a good fallback stack. If your fallback font has very different metrics than your web font, the swap causes layout shift. Match
font-size-adjustand x-height as closely as possible. - Forgetting
font-display: swapon lazy-loaded fonts. Without it, the browser may render invisible text until the font finishes downloading, which feels broken. - Using JavaScript to load fonts but not handling errors. If the font file 404s or times out, your page should still look acceptable with the fallback font.
- Loading all font weights upfront. If you only use
700for headings, don't also preload300,400,500, and600. Subset and load only what's needed. Our guide on optimizing web font file size covers this in detail. - Downloading Google Fonts via the external stylesheet URL. The
fonts.googleapis.comstylesheet creates an extra DNS lookup and connection. Self-hosting your fonts avoids this overhead and gives you full control over lazy loading.
Does lazy loading fonts affect SEO?
Google has stated that text must be visible and crawlable for proper indexing. If your lazy loading implementation causes text to be invisible for too long (using font-display: block with a long timeout), search engines might not render the content properly.
Using font-display: swap for critical text fonts keeps content visible at all times the fallback renders first, then swaps to your custom font. This is the safest approach for SEO. Google's crawlers use a rendering pipeline that processes JavaScript, so Intersection Observer-based lazy loading will work, but CSS-only approaches with media queries are the most reliable for ensuring content is always accessible.
Can you lazy load Google Fonts specifically?
Yes, but the default Google Fonts embed doesn't support lazy loading. When you paste the standard <link> tag from Google Fonts, the browser fetches the font CSS and font files synchronously.
To lazy load Google Fonts, self-host them first:
- Download the font files using a tool like google-webfonts-helper
- Convert them to WOFF2 format if they aren't already
- Define
@font-facerules withfont-display: swap - Apply the media query or Intersection Observer techniques described above
For example, you might self-host Source Serif Pro as your body font (preloaded) and lazy load Bebas Neue for a promotional banner that appears halfway down the page.
What tools can help you audit font loading performance?
- Chrome DevTools → Network tab: Filter by "Font" to see every font file, its size, and when it loaded relative to other resources.
- Lighthouse: The "Avoid enormous network payloads" and "Eliminate render-blocking resources" audits flag font-related issues directly.
- WebPageTest: Gives you a filmstrip view showing exactly when text swaps from fallback to web font.
- Coverage tab (DevTools): Shows what percentage of each font file's glyphs are actually used. If you're loading 200 KB of a font but using 40 KB of glyphs, you need to subset.
Practical checklist for lazy loading web fonts
- Audit your current fonts. Open DevTools Network tab and filter for font files. Note every font, its size, and when it loads.
- Identify critical vs. non-critical fonts. Fonts used above the fold are critical. Everything else can be lazy loaded.
- Self-host all fonts to eliminate the extra connection to Google's CDN.
- Convert to WOFF2 for maximum compression typically 30% smaller than WOFF.
- Preload critical fonts with
<link rel="preload">andfont-display: swap. - Lazy load secondary fonts using the
@media (min-width: 1px)CSS trick or an Intersection Observer. - Subset fonts to include only the characters and weights you actually use.
- Test with Lighthouse before and after. Compare LCP, FCP, and total blocking time.
- Verify with real users. Check that the fallback font doesn't cause noticeable layout shift when the web font swaps in.
How to Optimize Web Font File Size Without Losing Quality
Fastest Loading Web Fonts for Core Web Vitals: Top Optimization Strategies
WOFF2 vs WOFF: Font Performance Comparison for Modern Browsers
Best Lightweight Google Fonts for Faster Mobile Page Speed in 2025
Serif vs Sans-Serif for Web Design: How to Choose the Right Font
Best Serif Fonts for Website Body Text: Readability Guide