Fix Font Not Loading Issues: Complete Troubleshooting Guide
Comprehensive guide to diagnosing and fixing fonts that fail to load. Resolve CORS errors, path issues, format problems, and CSS syntax errors step by step.
In Simple Terms
Step 1: Open DevTools → Network tab → filter by Font. Check for 404 (wrong path), CORS errors (add Access-Control-Allow-Origin header), or no request (CSS syntax error).Common fixes: Verify font file paths are correct and case-sensitive, add format() hints to @font-face src, ensure WOFF2 files aren't corrupted.Still not working? Clear browser cache, check server MIME types (font/woff2 for .woff2), and test in incognito mode to rule out extensions.
In this article
Font loading failures are one of the most frustrating web development issues, causing text to display in fallback fonts or remain invisible until fonts load. When fonts fail to load, users see either a Flash of Unstyled Text (FOUT) with system fonts, or worse, a Flash of Invisible Text (FOIT) where content disappears entirely. These issues damage user experience, harm brand consistency, and can even make content unreadable.
Font loading problems stem from various sources: Cross-Origin Resource Sharing (CORS) restrictions blocking font downloads, incorrect file paths pointing to non-existent resources, unsupported font formats for specific browsers, malformed CSS syntax in @font-face declarations, and caching issues serving stale or corrupted files. Each cause requires a different diagnostic approach and solution.
This guide provides systematic troubleshooting for font loading failures. You'll learn to use browser DevTools to identify the root cause, fix CORS configuration on servers and CDNs, correct path and URL issues, ensure format compatibility across browsers, debug CSS syntax errors, and resolve caching problems. By following these diagnostic steps and solutions, you'll be able to quickly identify and fix any font loading issue.
Understanding Font Loading Issues
How Font Loading Works
Normal Font Loading Process:
- Browser parses HTML and encounters text with font-family
- Browser checks if font is available locally (system fonts)
- If not local, browser looks for @font-face declaration in CSS
- Browser downloads font file from specified URL
- Browser validates font file format and CORS permissions
- Browser applies font to text elements
- Text renders with custom font
When Loading Fails:
- • CORS Error: Font file blocked due to cross-origin restrictions
- • 404 Not Found: Font file doesn't exist at specified path
- • Format Error: Browser doesn't support the font format
- • CSS Syntax Error: @font-face declaration has invalid syntax
- • Network Error: Timeout, slow connection, or CDN issues
- • Cache Problem: Browser serving corrupted or outdated cached file
Visible Symptoms:
- • Text displays in fallback font (Arial, Times New Roman)
- • Text invisible for 3 seconds, then appears in fallback
- • Some fonts load, others don't (mixed success)
- • Fonts work locally but fail in production
- • Fonts work in one browser but not others
- • Intermittent loading (works sometimes, fails others)
Key Diagnostic Tool: Browser DevTools
The Network tab in browser DevTools (F12) is your primary diagnostic tool. It shows:
- • Whether font files are requested
- • HTTP status codes (200 OK, 404 Not Found, etc.)
- • CORS error messages
- • File sizes and load times
- • Response headers and MIME types
Common Causes
Cause 1: CORS (Cross-Origin Resource Sharing) Errors
Typical Error Message:
Access to font at 'https://cdn.example.com/font.woff2' from origin 'https://yoursite.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Why This Happens:
- • Font hosted on different domain/subdomain than website
- • Server doesn't send Access-Control-Allow-Origin header
- • Missing crossorigin attribute on preload links
- • CDN CORS settings not configured
- Note: CORS is required for ALL web fonts, even same-origin
Cause 2: Incorrect File Paths
Typical Error Message:
Failed to load resource: the server responded with a status of 404 (Not Found) GET https://yoursite.com/fonts/myfont.woff2 404
Common Path Mistakes:
- • Relative paths incorrect (../fonts/ vs ./fonts/)
- • Case sensitivity issues (Font.woff2 vs font.woff2)
- • Wrong root directory (public/ folder not considered)
- • File extension typos (.woff vs .woff2)
- • Spaces in filenames not URL-encoded
- • Build process not copying fonts to output directory
Cause 3: Unsupported Font Format
Browser Console Warning:
downloadable font: format not supported source: https://yoursite.com/fonts/font.woff2
Format Support Issues:
- • IE11 doesn't support WOFF2 (needs WOFF)
- • Old Safari versions don't support WOFF2
- • Only WOFF2 provided, no fallback formats
- • Wrong format() hint in @font-face
- • Corrupt or incomplete font file
Cause 4: CSS Syntax Errors
Silent Failures (No Error Message):
CSS syntax errors in @font-face often fail silently - the browser ignores the entire declaration without warning.
Common Syntax Mistakes:
- • Missing quotes around font-family name
- • Incorrect src: syntax (missing url() or format())
- • Missing semicolons
- • Wrong font-weight value (e.g., "bold" instead of 700)
- • Duplicate @font-face declarations conflicting
- • CSS comments breaking syntax (/* */ in wrong place)
Cause 5: Incorrect MIME Type
Browser Console Warning:
Resource interpreted as Font but transferred with MIME type text/html or application/octet-stream
MIME Type Issues:
- • Server not configured to send correct Content-Type header
- • WOFF2 served as application/octet-stream instead of font/woff2
- • WOFF served as text/plain instead of font/woff
- • Some browsers reject fonts with wrong MIME type
Cause 6: Cache and CDN Issues
Caching Problems:
- • Browser cache serving old/corrupt font file
- • CDN cache not invalidated after font update
- • Service worker caching outdated fonts
- • Proxy or firewall modifying font files
- • Mixed HTTP/HTTPS causing cache confusion
Diagnostic Steps
Step-by-Step Diagnostic Process
- Open Browser DevTools (F12)
- Press F12 or right-click → Inspect
- Go to "Network" tab
- Filter by "Font" or "All"
- Refresh page (Ctrl+R or Cmd+R)
- Check if Font Requests Are Made
- Look for .woff2, .woff, .ttf, .otf files in Network tab
- If NO requests appear: CSS syntax error or font-family not applied
- If requests appear: Check their status codes
- Examine Status Codes
- 200 OK: Font loaded successfully (check format/CSS if still not working)
- 404 Not Found: Path issue - file doesn't exist
- 403 Forbidden: Permission issue or CORS
- (failed): CORS error or network issue
- 304 Not Modified: Cached version used
- Check Console for Errors
- Switch to "Console" tab in DevTools
- Look for red error messages mentioning fonts or CORS
- Look for orange warnings about MIME types or formats
- Copy error messages for searching solutions
- Inspect Response Headers
- Click on font file in Network tab
- Go to "Headers" section
- Check "Response Headers" for:
- - Access-Control-Allow-Origin
- - Content-Type (should be font/woff2, font/woff, etc.)
- - Cache-Control
- Verify Font File Integrity
- Click on font file in Network tab
- Check "Size" - should be reasonable (20-200KB typically)
- If 0 bytes: File empty or redirect issue
- Try opening font URL directly in browser
Quick Diagnostic Checklist
- ☐ Font files present in Network tab?
→ If NO: CSS syntax error or font-family not used - ☐ Status code 200 OK?
→ If NO: Check specific error (404, 403, CORS) - ☐ CORS errors in console?
→ If YES: Fix server headers + add crossorigin attribute - ☐ Correct Content-Type header?
→ Should be font/woff2, font/woff, etc. - ☐ File size reasonable?
→ If 0 bytes or very large: Corruption or wrong file - ☐ Works with cache disabled?
→ If YES when cache disabled: Cache issue
Fixing CORS Issues
Solution 1: Configure Server CORS Headers
For: Self-hosted fonts on your own server
Apache (.htaccess):
# Add to .htaccess in fonts directory or root <FilesMatch "\.(woff2|woff|ttf|otf|eot)$"> Header set Access-Control-Allow-Origin "*" </FilesMatch> # Or allow specific domain only: <FilesMatch "\.(woff2|woff|ttf|otf|eot)$"> Header set Access-Control-Allow-Origin "https://yoursite.com" </FilesMatch>
Nginx (nginx.conf):
# Add to server block
location ~* \.(woff2|woff|ttf|otf|eot)$ {
add_header Access-Control-Allow-Origin "*";
}
# Or for specific domain:
location ~* \.(woff2|woff|ttf|otf|eot)$ {
add_header Access-Control-Allow-Origin "https://yoursite.com";
}Node.js / Express:
const express = require('express');
const app = express();
// Allow CORS for all font files
app.use('/fonts', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
// Or use cors middleware
const cors = require('cors');
app.use('/fonts', cors());Solution 2: Add crossorigin Attribute
Required for: Font preloading and cross-origin fonts
<!-- CRITICAL: crossorigin required even for same-origin fonts -->
<link rel="preload"
href="/fonts/myfont.woff2"
as="font"
type="font/woff2"
crossorigin>
<!-- For fonts from CDN -->
<link rel="preload"
href="https://cdn.example.com/fonts/font.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous">
<!-- Without crossorigin, fonts won't load! -->Important: The crossorigin attribute is required for ALL font preloads, even same-origin fonts, due to how browsers handle font requests.
Solution 3: CDN CORS Configuration
For: Fonts hosted on CDNs (Cloudflare, AWS CloudFront, etc.)
Cloudflare:
- 1. Go to Cloudflare Dashboard → Rules → Transform Rules
- 2. Create "HTTP Response Header Modification" rule
- 3. If URI Path matches:
/fonts/* - 4. Set response header:
Access-Control-Allow-Origin: *
AWS S3 Bucket CORS:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET"],
"AllowedOrigins": ["*"],
"ExposeHeaders": []
}
]Testing CORS Configuration
# Test CORS headers with curl curl -I -H "Origin: https://yoursite.com" https://cdn.example.com/fonts/font.woff2 # Look for this in response: # Access-Control-Allow-Origin: * # or # Access-Control-Allow-Origin: https://yoursite.com # If missing, CORS not configured correctly
Resolving Path Problems
Understanding Path Types
/* Absolute path (from domain root) */
@font-face {
src: url('/fonts/myfont.woff2');
/* Works from: https://yoursite.com/fonts/myfont.woff2 */
}
/* Relative path (from CSS file location) */
@font-face {
src: url('../fonts/myfont.woff2');
/* If CSS in /css/style.css, looks for /fonts/myfont.woff2 */
}
/* Full URL */
@font-face {
src: url('https://yoursite.com/fonts/myfont.woff2');
/* Explicit full URL */
}Common Path Fixes
Fix 1: Use Absolute Paths
/* BEFORE (problematic relative path) */
@font-face {
font-family: 'MyFont';
src: url('../fonts/myfont.woff2'); /* May break if CSS location changes */
}
/* AFTER (reliable absolute path) */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2'); /* Always works from domain root */
}Fix 2: Check Case Sensitivity
Linux servers are case-sensitive. Windows is not. This causes issues when deploying.
/* File named: MyFont.woff2 */
/* WRONG (case mismatch) */
src: url('/fonts/myfont.woff2'); /* Fails on Linux */
/* CORRECT (exact match) */
src: url('/fonts/MyFont.woff2'); /* Works everywhere */
/* BEST PRACTICE: Use lowercase filenames */
/* Rename file to: myfont.woff2 */
src: url('/fonts/myfont.woff2'); /* No case issues */Fix 3: URL-Encode Spaces and Special Characters
/* WRONG (spaces in filename) */
src: url('/fonts/My Font.woff2'); /* Breaks! */
/* CORRECT (URL-encoded) */
src: url('/fonts/My%20Font.woff2'); /* Works */
/* BEST PRACTICE: No spaces in filenames */
/* Rename to: my-font.woff2 or myfont.woff2 */
src: url('/fonts/my-font.woff2'); /* Best approach */Framework-Specific Path Issues
Next.js:
/* Fonts go in /public/fonts/ directory */
/* In CSS, reference from root: */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2');
/* NOT /public/fonts/myfont.woff2 */
}React (Create React App):
/* Fonts go in /public/fonts/ directory */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2');
/* or use %PUBLIC_URL% in HTML */
/* src: url('%PUBLIC_URL%/fonts/myfont.woff2'); */
}Vue.js:
/* Fonts in /public/fonts/ */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2');
}
/* Or fonts in /src/assets/fonts/ (webpack will process) */
@font-face {
font-family: 'MyFont';
src: url('~@/assets/fonts/myfont.woff2');
}Verifying Correct Paths
- Check Network Tab URL:
Look at the full URL the browser is requesting. Is it correct?
- Try Opening Font URL Directly:
Copy the font URL from Network tab, paste in browser address bar. Does it download?
- Verify File Exists on Server:
SSH into server or check file manager. Confirm file is actually there with correct name.
Format Compatibility
| Format | Browser Support | When to Use |
|---|---|---|
| WOFF2 | Chrome 36+, Firefox 39+, Edge 14+, Safari 10+, Opera 23+ ~97% of users | ✓ Primary format ✓ Best compression ✓ Modern sites |
| WOFF | IE9+, All modern browsers ~99% of users | ✓ Fallback for IE11 ✓ Old Safari support ✓ Legacy compatibility |
| TTF/OTF | All browsers (partial IE support) Universal | ✗ Avoid for web (no compression) ✓ Source files only |
| EOT | IE6-8 only <0.5% of users | ✗ Obsolete Only if supporting IE8 |
Recommended Format Stack
Modern Sites (97% coverage):
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2');
/* WOFF2 only - fast, small, modern */
}With IE11 Support (99% coverage):
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2'),
url('/fonts/myfont.woff') format('woff');
/* Browsers use first supported format */
}Maximum Compatibility (including old browsers):
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2') format('woff2'),
url('/fonts/myfont.woff') format('woff'),
url('/fonts/myfont.ttf') format('truetype');
/* Covers virtually all browsers */
}Common Format Mistakes
/* WRONG: Missing format() hint */
@font-face {
src: url('/fonts/myfont.woff2'); /* Browser may not recognize format */
}
/* CORRECT: Include format() */
@font-face {
src: url('/fonts/myfont.woff2') format('woff2');
}
/* WRONG: Wrong format hint */
@font-face {
src: url('/fonts/myfont.woff2') format('woff'); /* Incorrect! */
}
/* CORRECT: Matching format */
@font-face {
src: url('/fonts/myfont.woff2') format('woff2');
}CSS Syntax Errors
Common CSS Syntax Mistakes
Mistake 1: Missing Quotes
/* WRONG */
@font-face {
font-family: My Font; /* Missing quotes - breaks! */
}
/* CORRECT */
@font-face {
font-family: 'My Font'; /* Quotes required for names with spaces */
}Mistake 2: Wrong font-weight Values
/* WRONG */
@font-face {
font-family: 'MyFont';
src: url('/fonts/bold.woff2') format('woff2');
font-weight: bold; /* String "bold" is invalid! */
}
/* CORRECT */
@font-face {
font-family: 'MyFont';
src: url('/fonts/bold.woff2') format('woff2');
font-weight: 700; /* Numeric value required */
}Mistake 3: Missing Semicolons
/* WRONG */
@font-face {
font-family: 'MyFont' /* Missing semicolon */
src: url('/fonts/font.woff2') format('woff2') /* Missing semicolon */
}
/* CORRECT */
@font-face {
font-family: 'MyFont';
src: url('/fonts/font.woff2') format('woff2');
}Mistake 4: Incorrect src Syntax
/* WRONG: Missing url() wrapper */
@font-face {
font-family: 'MyFont';
src: '/fonts/font.woff2'; /* Breaks! */
}
/* WRONG: Missing quotes in url() */
@font-face {
src: url(/fonts/font.woff2) format('woff2'); /* May fail */
}
/* CORRECT */
@font-face {
font-family: 'MyFont';
src: url('/fonts/font.woff2') format('woff2');
}Correct @font-face Template
/* Perfect @font-face declaration */
@font-face {
font-family: 'MyFont'; /* Quotes required */
src: url('/fonts/myfont.woff2') format('woff2'), /* url() + format() */
url('/fonts/myfont.woff') format('woff'); /* Fallback */
font-weight: 400; /* Numeric value */
font-style: normal; /* normal or italic */
font-display: swap; /* Optional but recommended */
}
/* Using the font */
body {
font-family: 'MyFont', Arial, sans-serif; /* Quotes match @font-face */
}Validating CSS Syntax
- Use CSS Validator:
https://jigsaw.w3.org/css-validator/ - Paste your CSS to check for errors
- Check Browser Console:
CSS parsing errors appear in Console tab (though font-face errors often silent)
- Use VS Code Extensions:
"CSS Lint" extension highlights syntax errors as you type
Cache and CDN Issues
Clearing Browser Cache
Hard Refresh:
- • Windows/Linux: Ctrl + Shift + R or Ctrl + F5
- • Mac: Cmd + Shift + R
- • Bypasses cache and reloads all resources
Disable Cache in DevTools:
- Open DevTools (F12)
- Go to Network tab
- Check "Disable cache" checkbox
- Keep DevTools open
- Refresh page
Clear Specific Site Cache:
- • Chrome: Settings → Privacy → Clear browsing data → Cached images and files
- • Firefox: History → Clear Recent History → Cache
- • Safari: Develop → Empty Caches
Clearing CDN Cache
Cloudflare:
- Go to Cloudflare Dashboard
- Select your domain
- Go to Caching → Configuration
- Click "Purge Everything" or "Custom Purge"
- Enter font file URLs if using custom purge
AWS CloudFront:
# Create invalidation aws cloudfront create-invalidation \ --distribution-id DISTRIBUTION_ID \ --paths "/fonts/*" # Or invalidate specific file aws cloudfront create-invalidation \ --distribution-id DISTRIBUTION_ID \ --paths "/fonts/myfont.woff2"
Generic CDN Cache Busting:
/* Add version query parameter to force reload */
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont.woff2?v=2') format('woff2');
/* Change ?v=2 to ?v=3 when you update font */
}Service Worker Cache Issues
Check for Service Worker:
- Open DevTools → Application tab
- Look at "Service Workers" section
- If service worker exists, click "Unregister"
- Click "Clear storage" to remove cached fonts
- Refresh page
Update Service Worker to Not Cache Fonts:
// In service-worker.js
self.addEventListener('fetch', event => {
// Don't cache font files
if (event.request.url.includes('/fonts/')) {
return fetch(event.request);
}
// Cache other resources...
});Prevention Best Practices
Checklist for Reliable Font Loading
- ☐ Use correct @font-face syntax
- • Quotes around font-family
- • url() wrapper for paths
- • format() hints included
- • Numeric font-weight values
- ☐ Configure CORS headers
- • Access-Control-Allow-Origin: * on server
- • crossorigin attribute on preload links
- • CDN CORS settings enabled
- ☐ Use absolute paths
- • Start with / for domain root paths
- • Avoid relative paths (../)
- • Use lowercase filenames (no spaces)
- ☐ Provide format fallbacks
- • WOFF2 primary (modern browsers)
- • WOFF fallback (IE11, old Safari)
- • Both formats tested
- ☐ Set correct MIME types
- • font/woff2 for .woff2 files
- • font/woff for .woff files
- • Server configured correctly
- ☐ Test across browsers
- • Chrome, Firefox, Safari, Edge
- • Mobile browsers (iOS Safari, Chrome Mobile)
- • Use BrowserStack if needed
- ☐ Monitor in production
- • Check Network tab after deployment
- • Test with cleared cache
- • Verify CDN serving correctly
Production-Ready Font Loading Template
<!-- In HTML <head> -->
<link rel="preload"
href="/fonts/myfont-regular.woff2"
as="font"
type="font/woff2"
crossorigin>
<!-- In CSS -->
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-regular.woff2') format('woff2'),
url('/fonts/myfont-regular.woff') format('woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'MyFont';
src: url('/fonts/myfont-bold.woff2') format('woff2'),
url('/fonts/myfont-bold.woff') format('woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}
body {
font-family: 'MyFont', -apple-system, BlinkMacSystemFont,
'Segoe UI', Arial, sans-serif;
}
/* Server configuration (Apache .htaccess) */
<FilesMatch "\.(woff2|woff|ttf|otf)$">
Header set Access-Control-Allow-Origin "*"
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>Summary: Fixing Font Loading Issues
Font loading failures typically stem from CORS misconfigurations, incorrect file paths, unsupported formats, or CSS syntax errors. Use browser DevTools Network tab to diagnose the specific issue, then apply the appropriate fix: configure CORS headers for cross-origin fonts, use absolute paths for reliability, provide WOFF2 + WOFF formats for compatibility, and validate CSS syntax carefully.
Prevention is straightforward: use the production-ready template above, test across browsers before deploying, and always check DevTools after deployment to verify fonts load correctly. When issues occur, follow the diagnostic checklist to quickly identify and resolve the root cause.

Written by
Sarah Mitchell
Product Designer, Font Specialist

Verified by
Marcus Rodriguez
Lead Developer
