foit(文字空白等待字体加载)和fout(先用备用字体再替换)是浏览器处理未就绪web font的两种策略;前者由font-display: block触发,后者由swap触发,但swap仍可能导致布局偏移。

字体加载完成前的 FOIT 和 FOUT 是什么
HTML 字体加载时的“闪烁”不是视觉 bug,而是浏览器对未就绪字体的两种默认策略:FOIT(Flash of Invisible Text)和 FOUT(Flash of Unstyled Text)。前者让文字空白等待字体加载,后者先用备用字体渲染、等 Web Font 就绪后再重绘。两者都表现为“闪烁”,但成因和可控性完全不同。
-
font-display: block触发 FOIT:文字区域留白,直到@font-face加载完成或超时(通常 3s)才显示 -
font-display: swap触发 FOUT:立即用系统字体渲染,字体加载完成后无感替换 -
font-display: optional最激进:仅当字体已缓存才用,否则全程跳过——适合非关键文本
为什么 font-display: swap 不总能消除闪烁
即使写了 font-display: swap,仍可能看到两次重排:第一次是系统字体渲染,第二次是 Web Font 替换。如果两套字体的 line-height、letter-spacing 或字宽差异大,就会引发布局偏移(layout shift),用户感知为“跳动”而非“闪烁”。这不是字体没加载完,而是度量不一致。
- 检查
font-face中是否设置了size-adjust或ascent-override等 OpenType 属性来对齐度量 - 避免在
@font-face外部用font-size或line-height强制缩放——这会让 fallback 和 target 字体基线错位 - 用 Chrome DevTools 的 “Rendering” 面板勾选 “Layout Shift Regions”,直观定位跳动元素
preload 和 preconnect 对字体加载的实际影响
link rel="preload" 能提前触发字体资源下载,但只在字体路径明确、且没被 CSP 或同源策略拦截时生效;preconnect 对跨域字体 CDN(如 fonts.googleapis.com)有加速作用,但对本地 ./fonts/xxx.woff2 没意义。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 必须配
as="font"和type="font/woff2",否则浏览器可能忽略预加载或错误复用缓存 - 不要
preload所有字体变体:只预加载首屏最常用的那个(如 Regular,非 Bold/Italic) -
preconnect要写在顶部,且域名需与@font-face src完全一致(注意 https:// 与 // 协议前缀)
现代方案:font-face 的 descender-override 怎么用
Chrome 120+ 和 Safari 17.4+ 支持 OpenType 字体度量覆盖属性,可让 fallback 字体“假装”和 Web Font 有相同排版参数,从而彻底消除跳动。但它依赖字体文件本身嵌入了 OS/2 表,且只对 woff2 有效。
- 先用
opentype.js或fonttools查看目标字体的typoAscender/typoDescender值 - 在
@font-face中写:descender-override: -256;(数值来自字体工具输出) - 配套设置
size-adjust: 100%; ascent-override: 1024;才能完整对齐基线
这个方案目前兼容性有限,但对追求零布局偏移的关键产品(如设计系统官网)值得投入验证。别忘了 fallback 字体也得手动调 line-height 去拟合——浏览器不会自动帮你算。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










