加粗抖动主因是文本宽度变化触发重排,解决需预占加粗宽度:grid中用minmax(7.5rem,1fr)锁列宽;flex中用透明加粗文字+绝对定位伪元素显示常规文本;统一line-height为整数;禁用height过渡改用transform。

字体加粗后布局抖动,根本不是“动画不流畅”,而是文本宽度变化触发了重排(reflow)——font-weight从 400 变到 900 时,字符实际渲染宽度增加,若父容器列宽或行内尺寸依赖内容(如 minmax(0, 1fr)、inline-block 或未约束的 flex 项),就会被撑开,相邻元素被挤压,肉眼可见“一抽”。解决的关键不是压动画曲线,而是让布局提前“知道”加粗后的宽度。
用 minmax() 锁死网格列最小宽度
在 display: grid 场景下(比如响应式导航栏),抖动常来自 grid-template-columns: repeat(4, minmax(0, 1fr)) ——那个 0 允许列收缩到极限,也意味着它会随文本加粗实时伸缩。
- 把
minmax(0, 1fr)换成minmax(7rem, 1fr)或固定值8rem,确保列宽始终 ≥ 加粗文本最大可能宽度 -
7rem是经验值,需基于最长文案 + 加粗余量实测(例如 “Documentation” 加粗后宽度 ≈ 7.2rem,那就取7.5rem) - 保留
1fr上限仍可自适应,但下限已切断与文本度量的耦合 - 别只改
nav的grid,确认其父级div { display: flex }不干扰——它本身不导致抖动,问题在子nav的轨道计算
在 display: flex 中用伪元素 + 颜色切换预留空间
传统 ::after + opacity: 0 在 flex 容器里容易失效,因为伪元素会被当作独立 flex item 参与计算。更稳的做法是让主元素自己“占位”,再用伪元素覆盖显示:
- 主元素设
font-weight: 900; color: transparent;→ 占据加粗宽度,但不可见 -
::before设content: attr(data-text); font-weight: 400; position: absolute; z-index: 1;→ 显示常规文本 -
:hover时反转:color: currentColor;+::before { color: transparent; } - 必须给主元素加
position: relative;,否则::before会相对html定位,错位 - 若旁边有徽章(
badge),它和主元素同为 flex item,不受伪元素影响,布局完全稳定
避免 line-height 小数引发的叠加抖动
即使解决了加粗宽度问题,如果 line-height 计算结果是小数(如 font-size: 15px; line-height: 1.3; → 19.5px),配合过渡仍会因像素取整波动造成文字“上下跳”。
- 检查 DevTools 的
Computed面板,看line-height是否带小数点 - 改用整数值:
line-height: 20px,或调整font-size使乘积为整数(如16px × 1.25 = 20px) - 禁用
height过渡,改用transform: scaleY()—— 它不触发 layout,缩放中心可控 - 对文字容器加
will-change: transform;(JS 动画开始前动态加,结束后立刻移除),强制合成层隔离
最易被忽略的是:抖动往往是多个因素叠加的结果——font-weight 变宽 + line-height 小数取整 + flex 项未设 min-width,三者同时存在时,改掉任意一个都能止抖;但只调 transition-timing-function 或 font-smoothing,等于没碰根因。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











