The Problem
When loading web fonts (WOFF2, WOFF, TTF) from a CDN or different domain, the browser enforces CORS. If the CDN does not include the proper Access-Control-Allow-Origin header, the font fails to load and the browser falls back to system fonts.
Symptoms
- Custom fonts do not render, system fonts appear instead
- Console: "Font from origin has been blocked by CORS policy"
- Layout shift when fallback font loads first, then font fails
- Fonts load in Chrome but not Firefox (Firefox is stricter)
Real Error Message
Access to font at 'https://cdn.example.com/fonts/roboto.woff2'
from origin 'https://example.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the
requested resource.How to Fix It
Fix 1: Configure CDN CORS Headers
# On the CDN server (or origin server)
location ~* \.(woff2|woff|ttf|otf|eot)$ {
add_header Access-Control-Allow-Origin "https://example.com";
add_header Cache-Control "public, max-age=31536000";
}For AWS CloudFront, add CORS headers in the distribution settings or use Lambda@Edge:
// Lambda@Edge viewer response
exports.handler = async (event) => {
const response = event.Records[0].cf.response;
response.headers['access-control-allow-origin'] = [
{ key: 'Access-Control-Allow-Origin', value: 'https://example.com' }
];
return response;
};Fix 2: Use Crossorigin Attribute
<link
rel="preload"
href="https://cdn.example.com/fonts/roboto.woff2"
as="font"
type="font/woff2"
crossorigin="anonymous"
>Fix 3: Use Google Fonts with CORS Support
<!-- Google Fonts handles CORS automatically -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">Fix 4: Self-Host Fonts
@font-face {
font-family: 'Roboto';
src: url('/fonts/roboto.woff2') format('woff2'),
url('/fonts/roboto.woff') format('woff');
font-weight: 400;
font-display: swap;
}Self-hosting eliminates CORS issues entirely.
Fix 5: Verify CORS with curl
```bash curl -I https://cdn.example.com/fonts/roboto.woff2 \ -H "Origin: https://example.com"
# Look for: # Access-Control-Allow-Origin: https://example.com ```
Fix 6: Handle Font Loading Errors
```javascript const font = new FontFace('Roboto', 'url(/fonts/roboto.woff2) format("woff2")');
font.load().then(loadedFont => { document.fonts.add(loadedFont); document.documentElement.style.fontFamily = 'Roboto, sans-serif'; }).catch(err => { console.warn('Font failed to load:', err); // System fallback fonts will be used }); ```