当你希望页面上的文字在鼠标悬停时平滑变大,并写下 transition: font-size 0.3s 后,却发现文字“啪”地一下直接跳变,完全没有过渡动画。这并非你的代码写错,问题出在浏览器本身:它不会对 font-size 进行插值计算,尤其是在单位混用、包含 0 或继承值(如 inherit、
当你希望页面上的文字在鼠标悬停时平滑变大,并写下 transition: font-size 0.3s 后,却发现文字“啪”地一下直接跳变,完全没有过渡动画。这并非你的代码写错,问题出在浏览器本身:它不会对 font-size 进行插值计算,尤其是在单位混用、包含 0 或继承值(如 inherit、unset)的情况下,会直接跳过过渡过程。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
浏览器只对“能明确算出中间值”的属性执行过渡动画。而 font-size 在以下场景中,恰恰无法完成插值计算:
16px 过渡到 1.2em,浏览器无法在两者之间找到平滑路径。0、auto、initial、inherit 这类特殊值,插值计算链直接断裂。font-size 也在动态变化,子元素使用 em 单位时,计算链会变得复杂且不稳定。font-size,完全依靠继承得来。transition 找不到起点,自然无法“动起来”。transform: scale() 模拟字号变化这是最稳妥的路径。它走 GPU 合成层,不触发重排,所有现代浏览器都平滑支持。不过有几个细节需要注意:
display: inline-block 或 block,否则 transform-origin 无法生效。transform-origin: top left,可以避免文字上跳,特别适合标题、按钮等不牵连整体布局的场景。font-size 和 scale(),否则文字会出现模糊问题。标准示例:
.text {
display: inline-block;
transform-origin: top left;
transition: transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.text:hover {
transform: scale(1.25);
}
calc()如果你必须改变真实的 font-size,并且希望享受 CSS 的流畅过渡,可以考虑使用 @property 注册自定义属性。具体做法是:定义一个 --fs-multiplier,然后写 font-size: calc(var(--fs-multiplier) * 1rem)。但关键一步是,必须用 @property 将该变量注册为可动画类型,否则 transition 依然无效。这个方案对浏览器版本有要求(Chromium 110+ / Firefox 111+),适合响应式字号渐变,比如随视口宽度连续缩放。
如果你需要兼容老浏览器,或者必须精确控制动画,可以考虑用 requestAnimationFrame 逐帧更新 element.style.fontSize。但要注意,避免直接循环修改 style.fontSize——这会强制同步布局,导致严重掉帧。仅在必须精确控制或需配合其他逻辑(如 scroll 触发)时使用。
这些常见做法看似合理,实际不可靠:
transition: all 0.3s —— 会意外过渡 margin、border 等属性,引发布局抖动,得不偿失。font-size: 0 开始过渡 —— 几乎所有浏览器都不支持 0 到非零值的插值计算。em 单位,但父级字号也在变 —— 子元素过渡不同步,视觉上会卡顿。display: none 元素加 transition —— 完全不触发,因为元素已经脱离渲染流。真正需要想清楚的是:你要动的是“排版尺寸”(影响布局、需真实改变 font-size),还是“视觉尺寸”(只求看起来变大,用 transform 更稳)。前者在实际项目中极少需要动画,后者才是日常高频需求。理解了这一点,技术方案的选择就清晰多了。