如何通过JavaScript实现字体预下载缓存,优化后续页面字体渲染?
解决方案
核心思路是利用本地存储标记缓存状态+预加载分离渲染逻辑,既保证首次加载不影响FCP,又能让二次刷新直接用缓存字体,完全避免FOUT:
1. 先预加载字体但不关联渲染
在HTML头部添加预加载标签,先把字体下载到浏览器缓存,但不直接在初始CSS里使用它:
<link rel="preload" href="/path/to/your-font.woff2" as="font" type="font/woff2" crossorigin>
注意:
crossorigin必须加,哪怕字体和页面同域——浏览器对字体资源的预加载有跨域规则要求。
2. 初始CSS只使用系统 fallback 字体
页面首次加载时,全部文本用系统默认字体渲染,完全不触发自定义字体的加载和切换:
body { font-family: 'System UI', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
3. 用 localStorage 控制字体渲染时机
通过JS判断本地存储标记,决定是否加载自定义字体的样式:
// 页面初始化时检查缓存标记 const hasFontCache = localStorage.getItem('fontCached'); if (hasFontCache) { // 二次加载(已有缓存):直接注入font-face样式,立即用自定义字体 const fontStyle = document.createElement('style'); fontStyle.textContent = ` @font-face { font-family: 'YourCustomFont'; src: url('/path/to/your-font.woff2') format('woff2'); font-display: optional; /* 有缓存时立即渲染,无缓存时直接用fallback */ font-weight: 400; font-style: normal; } body { font-family: 'YourCustomFont', 'System UI', -apple-system, sans-serif; } `; document.head.appendChild(fontStyle); // 额外:验证字体是否真的加载成功,避免缓存失效的情况 document.fonts.load('400 16px "YourCustomFont"').catch(() => { localStorage.removeItem('fontCached'); }); } else { // 首次加载:监听预加载完成,标记缓存 const preloadLink = document.querySelector('link[rel="preload"][as="font"]'); if (preloadLink) { preloadLink.addEventListener('load', () => { // 字体下载完成,标记已缓存 localStorage.setItem('fontCached', 'true'); }); // 预加载失败时清除错误标记 preloadLink.addEventListener('error', () => { localStorage.removeItem('fontCached'); }); } }
关键细节说明
font-display: optional:这个属性是核心——它会告诉浏览器:如果字体在缓存里就立即用;如果没缓存,直接用fallback字体,完全不等待,从根源避免FOUT。- 缓存标记的可靠性:只有当预加载的字体确实下载完成后,才会设置
localStorage标记,确保二次加载时字体一定在缓存里。 - 缓存失效处理:通过
document.fonts.load()验证字体加载状态,万一用户手动清除了HTTP缓存但localStorage标记还在,会自动移除标记,下次加载重新走预加载流程。
如果你觉得内嵌样式不够整洁,也可以把font-face规则单独写在一个CSS文件里,然后动态创建<link>标签加载:
// 替换上面的内嵌样式逻辑 const fontLink = document.createElement('link'); fontLink.rel = 'stylesheet'; fontLink.href = '/path/to/font-styles.css'; document.head.appendChild(fontLink);
内容的提问来源于stack exchange,提问作者swlv
相关产品推荐
相关产品推荐

