核心要点
- 网页字体是导致视觉缺陷的重大来源,然而它们很少被纳入测试策略之中
- FOUT(未样式化文本闪现)和 FOIT(不可见文本闪现)对功能测试完全不可见,没有视觉捕获根本无法检测
- 不同操作系统之间的排版渲染差异会产生回归,只有跨平台视觉测试才能识别这些回归
- 自动化视觉测试是唯一能够大规模监控网站排版一致性的工具
网页排版,根据 W3C 的定义,是指 「在网页文档中使用字体,包括通过 @font-face 规则加载远程字体、通过 font-display 控制渲染行为,以及管理排版度量以确保一致的文本呈现」(W3C, CSS Fonts Module Level 4)。
这是学术定义。在实际工作中,网页排版是一片视觉雷区,大多数团队都在蒙着眼睛穿越。
你的用户可能不会有意识地注意到你使用了什么字体。但他们会立刻察觉到有什么不对劲。加载时跳动的文字。比预期更大的字符。溢出容器的标题。字母之间奇怪的间距。这些视觉上的微小瑕疵不断侵蚀着你网站的信任感和专业感。
最糟糕的是:你当前的测试很可能根本检测不到它们。
网页字体不是静态文件
关于网页字体的工作原理,存在一个广泛流传的误解。许多开发者把它们当作静态资源来处理:在 CSS 中声明字体,浏览器下载它,然后显示出来。就这么简单。
但实际上,加载网页字体是一个复杂的过程,包含多个故障点。浏览器必须先解析 CSS 以识别所需的字体。然后启动字体文件的下载,每个文件可能从几十到几百千字节不等。在下载过程中,浏览器必须决定显示什么替代内容。当字体最终到达时,浏览器必须将其光栅化并重新计算整个布局。
这些步骤中的每一步都可能产生与预期不同的视觉结果。而且每个浏览器、每个操作系统、每种网络配置处理这些步骤的方式都各不相同。
FOUT 和 FOIT:网页排版的两只幽灵
如果你从事 Web 开发工作,可能遇到过这些缩写。如果你从事 QA 工作,你应该把它们背得滚瓜烂熟,因为它们是两种最常见的排版类视觉缺陷。
FOUT — 未样式化文本闪现
FOUT 发生在浏览器于网页字体加载之前用后备字体显示文本,然后在字体到达后切换为最终字体时。用户看到文本「跳动」:单词改变大小,行重新分布,整个布局重新调整。
这个现象通常持续两百毫秒到几秒钟,具体取决于连接速度和字体文件大小。在信号覆盖较弱的移动网络环境下,它可能持续更长时间。
FOUT 不仅仅是美学上的小麻烦。如果用户在文本跳动的精确瞬间点击了按钮,他们可能会点偏目标。如果表单在用户输入过程中重新排布,用户会失去焦点。如果标题改变了大小并将下方内容向下推移,用户可能丢失自己的阅读位置。
FOIT — 不可见文本闪现
FOIT 是浏览器采用的另一种策略:它不显示后备字体,而是完全隐藏文本,直到网页字体加载完成。用户看到的页面上,本应有文字的地方变成了空白。
一些浏览器对 FOIT 设置了超时机制。Chrome 和 Firefox 最多隐藏文本三秒钟,之后回退到替代字体。然而 Safari 可以无限期地隐藏文本,只要字体没有加载完成。
想象一下:一位用户访问你的页面,标题消失了三秒钟。在这三秒钟内,你的页面看起来像是坏了。用户并不知道有字体正在加载。他们看到的是空白,并得出结论——你的网站出了问题。
为什么标准测试看不到它们
FOUT 和 FOIT 都不会触发 JavaScript 错误。没有 DOM 元素缺失。没有属性发生变化。文本内容存在且正确。从功能角度看,一切正常。
一个验证标题包含正确文本的 Selenium 测试会顺利通过,即使该标题因为 FOIT 而对用户不可见了三秒钟。一个点击按钮的 Cypress 测试也会成功,即使该按钮因为 FOUT 在用户点击的瞬间改变了位置。
只有能够捕获页面在加载过程中不同时刻的实际视觉外观的工具,才能检测到这些现象。这正是视觉测试所做的事。
后备字体:无声的危险
当网页字体完全无法加载时(CDN 不可用、文件被删除、CORS 错误、过于激进的广告拦截器),浏览器会使用 CSS 中声明的后备字体。如果没有声明后备字体,则使用系统默认字体。
问题在于,后备字体的度量与原始字体并不相同。字符高度不同。字母宽度不同。间距不同。字距调整也不同。
具体来说,一个为 Inter 字体中「确认我的订单」文字而设计大小的按钮,可能无法容纳 Arial 中的相同文本。文本溢出,或者按钮显得过大。一个在 Montserrat 下精确适配单行的标题,在 Helvetica 中可能换行成两行。你的整个布局都会偏移。
这些替换本应是暂时的(等待网页字体加载完成),但如果加载失败,它们就会变成永久的。而且由于不会产生任何错误,没有人会注意到——除了你的用户。
一个将页面外观与已知参考进行比较的视觉测试,能立即检测到后备字体的使用。度量上的差异,即使很微妙,也足以改变渲染效果并触发警报。
操作系统之间的渲染差异
这是许多开发团队不愿面对的事实:相同的字体、相同的 CSS,在 Windows、macOS 和 Linux 上不会以相同的方式显示。
原因是每个操作系统使用不同的字体光栅化引擎。Windows 使用 DirectWrite(前身是 ClearType)。macOS 使用 Core Text。Linux 使用 FreeType。每个引擎在抗锯齿、hinting、亚像素渲染和平滑处理方面做出不同的决策。
可见的结果是,同一字体和字号下,文本在 macOS 上看起来比在 Windows 上更粗。连字的渲染方式不同。自动字距调整也有所不同。在 Linux 上,渲染效果可能因发行版的 FreeType 配置而有显著差异。
这些差异逐字符来看很少是剧烈的,但在整个页面上会不断累积。macOS 上五行就能容纳的段落,在 Windows 上可能需要六行。Windows 上一行的标题,在 Linux 上可能需要两行。macOS 上能显示八个项目的水平菜单,在 Windows 上显示到第七个就不得不换行。
跨平台视觉测试通过在不同操作系统上运行相同的测试并为每个系统维护独立的基准截图来捕获这些差异。你不需要比较 Windows 渲染和 macOS 渲染(那样做毫无意义——它们永远不同)。你比较的是今天的 Windows 渲染与 Windows 基准,今天的 macOS 渲染与 macOS 基准。每个回归都在其对应的上下文中被检测到。
可变字体与新的缺陷来源
可变字体在单个文件中包含所有样式,拥有连续的变化轴(字重、字宽、倾斜度)。你不需要为每个样式加载一个文件,而是获得了无限的粒度。你可以指定 437 的字重,而不仅仅是「regular」(400)或「medium」(500)。
这种粒度对设计来说非常美妙。对视觉一致性来说却充满风险。如果开发者将字重从 400 改为 410,差异太微妙了,代码审查中根本注意不到。但对于细心的用户来说是可见的,尤其是当被修改的文本紧邻保持原始字重的文本时。
视觉测试配合适当校准的灵敏度阈值,能够检测到这些渐进式的排版漂移——无论是功能测试还是代码审查都无法捕获它们。
font-display 及其视觉后果
CSS 属性 font-display 控制浏览器在网页字体加载期间的行为。设置为 swap 时,浏览器先用后备字体显示文本再替换(必然产生 FOUT)。设置为 block 时,它短暂隐藏文本(必然产生 FOIT)。设置为 optional 时,如果连接速度较慢,浏览器可能决定永远不加载该字体。
每个值都是一个视觉权衡,其影响取决于上下文:连接速度、文件大小、同时加载的字体数量。一个模拟不同网络条件的视觉测试,可以捕获你的 font-display 选择的真实后果,并验证体验在所有条件下都保持可接受。
对感知性能和 SEO 的影响
排版直接影响 Cumulative Layout Shift(CLS),这是 Google 三个 Core Web Vitals 核心指标之一。每当后备字体被最终字体替换并导致文本重新排布时,就会产生 CLS。高 CLS 分数意味着糟糕的用户体验,并对你的搜索排名产生负面影响。
视觉测试检测的是导致 CLS 的症状:内容跳动、文本重新排布、尺寸变化。通过消除这些排版回归,你自然而然地改善了 CLS,从而提升 SEO 表现。
图标字体:一个关键的特殊情况
图标字体(Font Awesome、Material Icons)显示的是符号而非字母。当它们无法加载时,你的图标会变成空矩形或随机字符。你的导航、按钮、整个界面看起来全都坏了。
没有功能测试能检测到这个问题:DOM 是正确的,class 存在,属性也在。视觉测试能立即检测到图标的缺失。在这种情况下,它的附加价值是立竿见影且极为显著的。
构建排版视觉测试策略
排版值得专门的关注。创建针对关键排版场景的特定测试。
使用网络节流测试初始加载,验证你的 font-display 策略行为。阻止网页字体加载来测试后备字体是否能产生可接受的结果。在三个主要操作系统上使用独立的基准截图进行测试。并单独测试你的图标字体——通过阻止它们的加载。
排版不是细节
每个在测试策略中忽视排版的团队,事后都追悔莫及。排版缺陷非常狡猾:它们不会破坏任何功能,不会触发警报,也不会出现在日志中。它们默默地降低用户体验、侵蚀质量感知、影响 SEO。
自动化视觉测试是对抗这些隐形回归的唯一有效安全网。它能看到你的功能测试看不到的东西。它能检测到你疲惫的眼睛在冲刺结束时忽略的东西。它能监控没有人有时间手动监控的东西。
因为排版不是设计细节。它是你内容的载体。如果载体坏了,它所承载的内容质量再好也无济于事。
常见问题
视觉测试如何区分有意的字体更改和缺陷?
它不能自动区分,这是一个重要的要点。视觉测试检测的是与基准截图的任何差异。由团队来判断差异是有意的(品牌指南更新、刻意的字体更换)还是意外的(后备字体、捕获到的 FOUT、回归)。这就是为什么定期更新测试基准至关重要:当你有意更改排版时,同步更新基准,让测试反映新的预期状态。
视觉测试能检测到仅持续几百毫秒的 FOUT 吗?
可以,前提是测试被配置为在正确的时刻捕获页面。大多数视觉测试工具允许在特定的加载时刻截取屏幕截图,包括在网页字体完全加载之前。通过结合「首次渲染时」和「完全加载后」的截图,你可以同时验证加载行为和最终结果。
每个浏览器和操作系统需要不同的测试基准吗?
是的,这是一个经常被忽视的最佳实践。排版渲染在 Chrome、Firefox 和 Safari 之间,以及在 Windows、macOS 和 Linux 之间都有差异。为所有环境使用单一基准会产生持续的误报。通过为每个浏览器-操作系统组合维护特定基准,你只检测真实的变化,而非平台之间正常的渲染差异。
Google Fonts 比自托管字体更可靠吗?
从可用性角度看,Google Fonts 受益于 Google 极其可靠的 CDN 基础设施。然而它们引入了一个你无法控制的第三方依赖。Google 可以修改提供的字体文件(而且为了优化文件大小已经这样做过)。广告拦截器可以阻止对 Google 域名的请求。从视觉测试的角度看,自托管减少了变量,提供了更可预测和更可测试的结果。
如何在视觉测试策略中处理可变字体?
可变字体增加了连续的变化轴(字重、字宽、倾斜度)。对你 CSS 中实际使用的轴值进行视觉测试。如果你使用了 400、500 和 700 字重,分别为每个值捕获基准截图。可变字体的主要风险是意外修改轴值(例如将 400 改为 410)。具有适当灵敏度阈值的视觉测试能检测到这些代码审查系统性遗漏的微妙变化。
视觉测试能帮助选择合适的后备字体吗?
间接地可以。通过在测试中阻止网页字体加载并捕获后备字体的渲染结果,你能精确看到用户在字体无法加载时看到的内容。这让你能够选择度量接近主字体的后备字体,最小化 FOUT 的视觉跳动,并确保即使没有网页字体也能提供可接受的体验。
延伸阅读
你的网页字体是一个没人监控的视觉缺陷来源?是时候改变这种状况了。