现象
手上有两个后台项目,都跑在同一台 Mac、同一个 Chrome 里,用的是同一套视觉规范。把它们并排放着看,其中一个项目的文字明显更细:标题、表头、侧边栏、空状态,全都像"掉了一档字重"。
但打开 DevTools 对同一个元素逐项比对,结果却是:
font-family完全一样font-size完全一样font-weight完全一样color完全一样
代码里也找不到任何第二份字体文件,更没有 font-weight: 300 之类的降级写法。
问题到底出在哪?

| 粗的字体放大后 | 细的管理放大后 |
|---|---|
![]() |
![]() |
排查:先把"字体本身"排除掉
遇到"同字重不同粗细",直觉一般会往三个方向找:
- 字体文件不同:一边真的在用系统字体,另一边回退到了某个没加载成功的 Web Font。
- 字重被覆盖 :某个组件库或全局样式偷偷把
font-weight改成了 400 甚至 300。 - 缩放不同:截图尺寸、浏览器缩放、DPR 不一致,导致肉眼误判。
前两个直接用 DevTools 的 Computed 面板就能排除:两边最终生效的字体栈都是
css
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, "Noto Sans", sans-serif, ...;
font-weight 都是 400,color 也一样。第 3 点则可以通过量像素排除:两边的表格表头字号都是 14px,截图中字形高度都正好是 12px,说明渲染比例一致,不存在"一边被缩小了"的情况。
既然字体、字号、字重、颜色都一致,那就只剩最后一个变量:浏览器怎么把这些笔画画到屏幕上。
定位:Computed 面板里的一行属性
在 DevTools 里选中 body,Computed 面板过滤 font-smoothing:
| 项目 A(偏粗) | 项目 B(偏细) | |
|---|---|---|
-webkit-font-smoothing |
auto |
antialiased |
-moz-osx-font-smoothing |
auto |
grayscale |
text-rendering |
auto |
optimizeLegibility |
项目 B 比项目 A 多了三项全局字体渲染属性,而且是在 body 上生效的。再往上一层查来源,发现项目 B 里其实有两处都在开启"细体模式":
第一处,业务自己的 reset:
less
/* src/assets/styles/reset.less */
body {
width: 100%;
height: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
第二处,组件库自带的 normalize:
css
/* @arco-design/web-vue/dist/arco.css(2.55.x) */
html {
line-height: 1.15;
-webkit-text-size-adjust: 100%;
-webkit-font-smoothing: antialiased; /* chrome、safari */
-moz-osx-font-smoothing: grayscale; /* firefox */
}
也就是说,即使业务代码里删掉第一处,Arco 的 CSS 也会在 html 上把整个页面的字体渲染设成 antialiased。
而项目 A 用的是 Ant Design Vue,它的 dist CSS 里只有图标类才会开启这个属性:
css
/* ant-design-vue/dist/antd.css(4.x) */
.anticon {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
正文没有任何全局设置,走的是浏览器默认值。
根因:antialiased 会让文字"变细"
-webkit-font-smoothing 是一个非标准属性,只在 macOS 上的 Chrome / Safari 生效。它控制的是字体抗锯齿方式:
auto(默认):使用平台的默认渲染,也就是 subpixel-antialiased。浏览器会做一定程度的字体平滑(font smoothing),笔画边缘会被适度加重,看起来更实。antialiased:强制使用灰阶抗锯齿,同时关掉上述的笔画加重效果。文字因此变得更"轻"、更细。none/subpixel-antialiased:一般不需要手动使用。
-moz-osx-font-smoothing: grayscale 是 Firefox 在 macOS 上的对应属性,效果类似。
这里有个容易误解的点:macOS 10.14 Mojave 之后,系统层面已经取消了 RGB 子像素抗锯齿,很多人以为这几个属性"没用了"。实际上浏览器内部对字体平滑的处理依然存在,antialiased 依旧会关掉那层轻微的笔画加重,所以在 Retina 屏上仍然肉眼可辨------尤其是 14px 左右的中文正文。
另外,这个差异只在 macOS 上成立 。Windows / Linux 下 Chrome 不响应 -webkit-font-smoothing,如果两个人跨系统对比,这一条解释不了任何现象。
修复
目标很明确:让项目 B 的正文回到浏览器默认渲染,和项目 A 保持一致。
less
body {
width: 100%;
height: 100%;
-webkit-font-smoothing: auto;
-moz-osx-font-smoothing: auto;
}
顺手把 text-rendering: optimizeLegibility 也去掉。它不改变字重,只影响 kerning 和连字,但没必要为一个排查不清的渲染差异再增加一个变量。
为什么写在 body 上,而不是 html 上?
因为 -webkit-font-smoothing 是可继承属性。
组件库把 antialiased 写在了 html 上,所有后代元素默认继承这个值。只要在 body 上显式声明 auto,body 及其后代就不再使用从 html 继承来的值了------优先级不需要比库的规则高,因为这是"自己的声明 vs 继承值",不是同元素上的规则竞争。
如果反过来把覆盖写在 html 上,就得考虑和库 CSS 的加载顺序、选择器优先级,稳定性会差很多。
需要额外注意的地方
- 如果项目里用了 Tailwind 的
antialiased类,或者图标字体自己写了antialiased,这些元素仍会保持细体,需要按需处理。 - 给元素加
transform、opacity、will-change等触发合成层的属性,也可能让浏览器退回灰阶抗锯齿。所以排查时不要只看全局样式,也要看目标元素自身。 - 是否要全局开启
antialiased,本质上是设计取舍。很多设计系统为了"更干净"会主动开启,但前提是设计稿和验收环境都在同一渲染模式下 。最怕的是设计稿按系统默认渲染出图,开发环境却全局开了antialiased,然后大家对着截图反复怀疑字重。
两个可复用的排查技巧
1. 用 Computed 面板做"渲染属性 diff"
除了 font-family / font-weight / color,还应该顺手看一眼:
js
const cs = getComputedStyle(document.body);
console.log({
fontFamily: cs.fontFamily,
fontSize: cs.fontSize,
fontWeight: cs.fontWeight,
color: cs.color,
webkitFontSmoothing: cs.getPropertyValue('-webkit-font-smoothing'),
mozOsxFontSmoothing: cs.getPropertyValue('-moz-osx-font-smoothing'),
textRendering: cs.textRendering
});
两个页面各跑一次,逐项对比,比肉眼盯半天有效得多。
2. 截图不要直接比"看起来"
不同窗口宽度、不同缩放的截图放在一起,元素相对大小会严重干扰判断。正确姿势是先量一个可锚定的指标(比如同字号文字的字形像素高度),确认两边渲染比例一致,再比较笔画。
如果还想更客观一点,可以统计文字区域的"墨量密度"(暗像素占包围盒的比例)。这次排查中,两张图表头字号相同,但开启了 antialiased 的那张墨量密度明显更低,和肉眼观感一致。
结论
"同样的 font-weight,一边看起来更细",在 macOS 上首先要查的不是字体文件,也不是字重,而是:
css
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
特别是使用 Arco Design 的项目------它打包的 normalize 会在 html 上全局开启这两个属性,而 Ant Design、Element Plus 等库大多只用在图标上。从别的组件库迁过来时,这种"全局细一圈"的观感差异,很可能就来自这里。
排查清单:
- 确认两边系统、浏览器、缩放一致(跨系统时该属性不适用)。
- DevTools 对比
font-family/font-size/font-weight/color。 - 过滤 Computed 里的
font-smoothing/text-rendering。 - 检查组件库自带的 normalize / reset,而不只是业务代码。
- 需要覆盖时,写在
body上,把继承值截断。

