最轻量稳定的动效方案是仅用transform和opacity,因其不触发重排重绘,只走GPU合成;transition须写在常态,避免all和错误触发,配合pointer-events等实现完整交互。

直接用 transform 和 opacity 做过渡,是目前最轻量、最稳定、最不容易翻车的动效方案。只要写对了触发方式和属性组合,99% 的基础交互动画都能丝滑跑起来。
为什么只选 transform 和 opacity?
这两个属性被浏览器标记为“可合成层(composited)”属性,变化时不会触发 layout(重排)或 paint(重绘),只走 GPU 合成管线,帧率稳、功耗低。而像 top、left、width、height 这类属性,一动就可能引发整页重排,卡顿肉眼可见。
常见错误现象:top: 0 → top: 10px 加了 transition 却掉帧;元素在动画中边缘发虚;移动端触控后动画延迟半拍。
- 必须用
transform: translateY(0)替代top,用transform: scale(1)替代width/height缩放 -
opacity是唯一能安全控制“显隐+渐变”的基础属性,值域是0~1,连续可插值 - 避免混用
visibility或display—— 它们不可动画,且会打断transform/opacity的合成链
transition 写法必须放在常态上
把 transition 写在 :hover 或 .active 里,会导致回弹无动画 —— 这是新手最常踩的坑。
立即学习“前端免费学习笔记(深入)”;
正确做法是:过渡声明始终放在元素默认状态(常态)中,靠状态切换触发变化。
.btn {
opacity: 1;
transform: scale(1);
transition: opacity 0.25s ease, transform 0.25s ease;
}
.btn:hover {
opacity: 0.7;
transform: scale(1.05);
}
- 不要写
transition: all 0.25s—— 容易意外触发其他属性动画(比如box-shadow变化也跟着动) - 时间值建议统一,如都用
0.25s或0.3s,避免两个动画不同步 - 缓动函数优先用
ease-out或cubic-bezier(0.25, 0.8, 0.25, 1),比默认ease更自然
需要隐藏空间时,不能只靠 opacity
opacity: 0 后元素依然占位、仍可点击(除非加 pointer-events: none)。如果目标是“完全退出交互流”,得配合其他手段。
常见使用场景:下拉菜单收起、提示框自动关闭、折叠面板隐藏内容。
- 仅视觉隐藏 → 只用
opacity+transition即可 - 需释放布局空间 → 必须搭配
max-height+overflow: hidden,或用 JS 切换display: none(但要在opacity动画结束后再切) - 要防误点 → 在
opacity: 0状态同时加pointer-events: none,恢复时再加回来
性能微调:will-change 不是万能钥匙
will-change: transform, opacity 确实能提前提示浏览器创建独立图层,但滥用反而增加内存开销,尤其在列表项或高频动画中。
真实项目里,只在以下情况加:
- 动画频繁触发(如滚动视差、拖拽跟随)
- 元素层级深、父容器有复杂
filter或mask - 调试发现 FPS 波动明显,且已确认是合成层未提升
绝大多数悬停、点击类动效,不加 will-change 更稳妥 —— 浏览器自己能判断,你硬塞反而干扰优化逻辑。
真正难的不是写出这段 CSS,而是想清楚:这个动效到底要解决什么交互意图?是提示状态变化,还是引导用户视线,还是掩盖异步加载延迟?属性选对只是起点,节奏、延迟、中断响应这些细节,才决定它最终是“顺手”还是“碍事”。


















