F4.15.3webfont metric mismatch CLS设计
回退字体与目标字体的度量差异会造成加载后的布局跳动
别名: 字体度量 · CLS · fallback metrics · size-adjust
概念解释
后备字体先画上去,自定义字体一到,字母宽度、字身高度、行盒都可能变,已经排好的行会重排,下面的按钮被顶走。这是度量不匹配造成的布局跳动(metric mismatch / cumulative layout shift),不是「换了个更好看的脸」那么轻。FOUT 让字尽早可见,账单在这一跳上。
机制
字体的度量是一套数字:x 高度、升部、字宽、默认行高。两张脸的数字对不上,同样的字符序列占的盒子就不同。换脸等于把一段已经布局完的文本换成另一套盒子,后续块的位置全部重算。用户若正在点那个被顶走的按钮,点到的是新上来的别的东西。跳动的大小跟两张脸的差异成正比,跟这段文本的面积成正比:导航上几个词跳一点,一篇文章跳整屏。补救不是回到隐形等待,而是让两张脸的度量靠近——选度量相近的后备,或用覆盖度量(如 size-adjust、ascent-override)把后备「假装」成目标脸的盒子,换脸时盒子几乎不变,变的只有轮廓。
边界
两张脸几乎是同一家族的不同文件(可变字体的轴、同一设计的网页版与系统版),跳动可以小到看不出。阻塞到自定义字体到达才绘制,没有换脸,也就没有这一种跳动——那是用 FOIT 换掉了 CLS,不是度量被修好了。图标、不参与文档流的绝对定位字标,跳了也不挤别人。用户正在滚动时发生的换脸,跳动会被滚动本身盖住,但停下来读的时候仍会感到段落在挪。
怎么落地
- 为正文指定度量接近的后备字体,或给
@font-face写度量覆盖,让换脸前后行宽和行数尽量不变。 - 在换脸瞬间截前后两帧叠在一起,看行末和下面按钮挪了多少。导航和第一屏正文若发生明显重排,先改度量,不要先改回长时间空白。
- 用布局偏移作为验收:自定义字体到达不应把主按钮移出原先的点击位置。