我常在下载页面上看到这样的进度:右侧那串“已下载 37.2 MB”一直在轻轻发抖,数字本身没错,可每涨一下,整串文字就往左或往右挪一点点。问题不在布局,而是字体里每个数字本来就不一样宽。换成等宽数字,抖动就没了。
最近一秒,左边缘来回移动了 0 px
“1”比“0”窄一大截。数字每跳一下,整串的宽度就变一次,右对齐的左边缘跟着来回晃;账单里的小数点也偏离了虚线。
最近一秒,左边缘来回移动了 0 px
同一个字体,只是让每个数字占一样宽。秒表只有数字在变,位置纹丝不动;账单的小数点和千分位自然排成一条竖线。
等宽数字解决了“抖”,数字变化本身还是一下跳过去的。价格、余额、计数这种值得被注意到的变化,可以让每一位像拨号盘一样滚到新值:变了多少、往哪个方向变,一眼就看得到。右边用的是 NumberFlow,一个很小的开源组件,系统开启减少动态效果时会自动不滚。
为什么这样更好#
- 比例数字是为句子设计的。字体默认让“1”窄一些、“0”宽一些,夹在文字里读起来更匀称。可放进计时器、计数器里,数字每变一次,整串的宽度也跟着变。
- 右对齐会把宽度变化变成晃动。右端固定,宽度一变,左边缘就来回跳。眼睛会被这点抖动一直吸引过去,注意力反而离开了数字本身。
- 等宽数字只让内容变,不让位置变。每一位数字占一样宽,秒表从 09 走到 11,字形换了,位置没动。读的人看到的是“数在涨”,而不是“文字在抖”。
- 表格里的数字要能竖着比。等宽数字让相同位数的数字更容易对齐;若要让小数点也排成一列,还需统一整数位宽或单独按小数点对齐。
- 通常不用换字体。大多数现代字体同时带着两套数字,只是默认用比例那一套。打开等宽数字这个开关就够了,不必为了数字专门换一套等宽字体。
我的习惯是:只要一个数字会在用户眼前变化,或者会和上下几行放在一起比较,就默认用等宽数字。
再进一步:让数字滚过去#
等宽数字解决的是“抖”,但数字变化本身仍然是一下跳过去的。对价格、余额、点赞数这种值得被注意到的变化,我更喜欢让每一位像拨号盘一样滚到新值:涨了还是跌了、变了多少,不用盯着前后两个数去比。
demo 最下面那组用的是 NumberFlow ↗,Maxwell Barvian 做的开源数字动画组件。它把格式化交给浏览器自带的数字格式(货币、千分位、单位都能用),无需额外的格式化库;使用 NumberFlow 本身仍需安装对应的组件包。系统开启减少动态效果时会自动不滚,React、Vue、Svelte 都有对应的版本。想给自己的页面加上这种效果,把这个链接丢给你的 Agent 就够了。
什么时候不该用#
- 正文段落里的数字,比如“去年读了 11 本书”。它不会变,也不和谁对齐,比例数字读起来更自然。
- 大号的展示数字,比如封面上的年份、营销页上的单个统计数字。这时字形之间的间距比对齐更重要,等宽数字里“1”两边会显得空。
- 如果字体本身没有等宽数字这套字形,打开开关也不会生效。用之前先在页面上看一眼实际效果。
- 滚动数字只给真正值得注意的变化。每帧都在跳的秒表、下载进度用滚动反而更乱,等宽数字就够了。
出处#
Vercel 的 Web Interface Guidelines ↗ 在 Content 一节里专门写了一条:需要比较的数字用等宽数字,或者直接用等宽字体。两套数字的定义可以参考 MDN 的 font-variant-numeric ↗。滚动数字来自 NumberFlow ↗。