同样的 font-weight,为什么这个项目的字体就是更细?

现象

手上有两个后台项目,都跑在同一台 Mac、同一个 Chrome 里,用的是同一套视觉规范。把它们并排放着看,其中一个项目的文字明显更细:标题、表头、侧边栏、空状态,全都像"掉了一档字重"。

但打开 DevTools 对同一个元素逐项比对,结果却是:

  • font-family 完全一样
  • font-size 完全一样
  • font-weight 完全一样
  • color 完全一样

代码里也找不到任何第二份字体文件,更没有 font-weight: 300 之类的降级写法。

问题到底出在哪?

粗的字体放大后 细的管理放大后

排查:先把"字体本身"排除掉

遇到"同字重不同粗细",直觉一般会往三个方向找:

  1. 字体文件不同:一边真的在用系统字体,另一边回退到了某个没加载成功的 Web Font。
  2. 字重被覆盖 :某个组件库或全局样式偷偷把 font-weight 改成了 400 甚至 300。
  3. 缩放不同:截图尺寸、浏览器缩放、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 等库大多只用在图标上。从别的组件库迁过来时,这种"全局细一圈"的观感差异,很可能就来自这里。

排查清单:

  1. 确认两边系统、浏览器、缩放一致(跨系统时该属性不适用)。
  2. DevTools 对比 font-family / font-size / font-weight / color。
  3. 过滤 Computed 里的 font-smoothing / text-rendering。
  4. 检查组件库自带的 normalize / reset,而不只是业务代码。
  5. 需要覆盖时,写在 body 上,把继承值截断。
相关推荐
程序员20071 小时前
抽卡玄学?不,是数学:保底机制下出货概率到底怎么算
前端
excel1 小时前
请求很慢,问题一定出在服务器吗?看懂浏览器网络耗时
前端·后端
代码猎人1 小时前
前端怎么熟悉ES6+语法
前端
代码猎人1 小时前
前端怎么精通Vue2核心原理
前端
夏天要喝冰可乐1 小时前
我用 WorkBuddy 做了个「GitHub 考古所」:输入一个用户名,出土你的编程人格档案
前端·github
乘风gg1 小时前
AI coding 时代最值钱的东西,软件工程(下)
前端·ai编程·claude
DGT1 小时前
不用 LangChain,200 行 TypeScript 手搓一个能联网、能写文件的 Agent
前端·langchain·agent
用户11481867894841 小时前
虚拟滚动与无限滚动的完整心法
前端
核验笔记的老王1 小时前
前端表单防呆实践:如何排查自动填充导致的提交失败?
前端