How to Optimize Fonts (font-display, preload, subsets)
Fonts are a common performance bottleneck in WordPress themes.
A few small changes can reduce render blocking, prevent invisible text (FOIT),
and cut font download size significantly.
This guide covers the three highest-ROI font optimizations:
- font-display to control text rendering behavior
- preload for critical font files
- subsets to reduce font file size
Step 1: Prefer Self-Hosted Fonts (Control + Cache)
When you self-host fonts in your theme (or a must-use plugin),
you control:
- Cache headers
- Preload behavior
- Subsets and formats
- Privacy (no third-party requests)
Place font files in a predictable location, for example:
/assets/fonts/
Step 2: Use WOFF2 First (Modern Baseline)
Use WOFF2 whenever possible. It’s the best balance of compression and browser support.
A practical default is:
- WOFF2 only for modern sites
- WOFF fallback only if you must support older browsers
Step 3: Set font-display (Fix FOIT/FOUT)
By default, browsers may hide text until fonts load (FOIT).
For performance-focused sites, you usually want text to render immediately.
Add font-display: swap to your @font-face rules:
@font-face {
font-family: "Inter";
src: url("/wp-content/themes/your-theme/assets/fonts/inter-latin-400.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
Which font-display Value Should You Use?
- swap: fastest perceived rendering, most common choice
- optional: can skip font download on slow connections (more aggressive)
- fallback: short block period, then fallback
Most themes should start with swap.
If you want to be more aggressive (especially for non-brand-critical body fonts),
consider optional.
Step 4: Subset Fonts (Biggest Byte Reduction)
If you ship full Unicode fonts, you’re often downloading hundreds of KB or more per weight.
Subsetting is the highest-impact optimization:
- Latin only
- Latin-extended if needed
- Japanese fonts should be treated separately (often very large)
A practical approach is to host multiple subset files and let CSS pick by language
using unicode-range.
Example: Latin Subset with unicode-range
@font-face {
font-family: "Inter";
src: url("/wp-content/themes/your-theme/assets/fonts/inter-latin-400.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
Now the browser downloads this subset only when needed.
Step 5: Preload Only the Fonts Needed for Above-the-Fold Text
Preloading can improve first render by starting the font request early.
But preloading too many fonts wastes bandwidth and can slow down LCP.
Only preload:
- The exact WOFF2 file used for body text above the fold
- At most 1–2 font files per page in most cases
Preload a Self-Hosted Font in WordPress
Add a preload tag in wp_head.
<?php
add_action( 'wp_head', function () {
// Example: preload only on front page or specific templates if needed
if ( ! is_front_page() ) return;
$href = get_theme_file_uri( '/assets/fonts/inter-latin-400.woff2' );
echo '<link rel="preload" href="' . esc_url( $href ) . '" as="font" type="font/woff2" crossorigin>' . "\n";
}, 1 );
Notes:
- Use
as="font"andtype="font/woff2" - Include
crossoriginfor fonts (safe default) - Scope the preload (front page only, or where it matters)
Step 6: Avoid Loading Too Many Weights
Every font weight is typically a separate file.
A common theme mistake is loading 6 weights “just in case”.
Practical defaults:
- Body: 400
- Headings: 600 or 700
If you need intermediate weights, consider variable fonts—but preload carefully.
Step 7: Ensure Fonts Don’t Block LCP (Balance Preload vs Images)
If your LCP element is an image, over-preloading fonts can compete for bandwidth.
If your LCP element is large text (hero heading), fonts matter more.
A good strategy:
- Text LCP page: preload 1 font file for the hero text
- Image LCP page: consider no font preload, or preload only the body font
Step 8: Serve Long Cache Headers for Font Files
Fonts should be cached aggressively because they rarely change.
If you version your assets (recommended), you can safely use long cache lifetimes.
At the theme level, do two things:
- Version the URL when you change fonts (e.g., filemtime)
- Configure server cache headers if possible
Even without server config access, versioned URLs prevent stale cache issues.
Recommended Implementation Pattern (Theme)
- Self-host WOFF2 fonts under
/assets/fonts/ - Create subsets (Latin / Latin-ext) or minimal sets for your audience
- Add
@font-facewithfont-display: swap - Load only 2 weights (400/700) unless proven necessary
- Preload only the 1 critical above-the-fold font file
Example: Minimal Font Setup for a WordPress Theme
1) Add CSS (global stylesheet):
@font-face {
font-family: "Inter";
src: url("/wp-content/themes/your-theme/assets/fonts/inter-latin-400.woff2") format("woff2");
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Inter";
src: url("/wp-content/themes/your-theme/assets/fonts/inter-latin-700.woff2") format("woff2");
font-weight: 700;
font-style: normal;
font-display: swap;
}
body {
font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
2) Preload only the body font on critical templates:
<?php
add_action( 'wp_head', function () {
if ( ! is_front_page() ) return;
$href = get_theme_file_uri( '/assets/fonts/inter-latin-400.woff2' );
echo '<link rel="preload" href="' . esc_url( $href ) . '" as="font" type="font/woff2" crossorigin>' . "\n";
}, 1 );
Common Mistakes
- Preloading multiple font weights “just in case”
- Using full Unicode fonts for Latin-only sites
- Forgetting
font-display(FOIT) - Hosting fonts on third-party domains without a reason
- Letting fonts compete with LCP images via excessive preloads
Summary
font-display: swapprevents invisible text and improves perceived speed- Subsetting reduces the biggest cost: font file size
- Preload only the font needed for above-the-fold text
- Limit font weights and use WOFF2
- Self-hosting gives you full performance and privacy control
Fonts are one of the easiest “silent wins” for WordPress performance.
A minimal, intentional font strategy improves both UX and Core Web Vitals without plugins.
🎨 Want to learn more? Visit our WordPress Customization Hub for tips and advanced techniques.