css动画核心是视觉节奏、性能与dom行为的平衡;应按场景选transition(状态切换)或animation(复杂时序),避免触发布局、滥用timing-function,并谨慎用js控制。

css动画没有“全景手册”,更不存在“100个秘诀”这种打包销售式知识——动效的本质是视觉节奏、性能约束与 DOM 行为的三方博弈,不是凑数技巧的堆砌。
animation 和 transition 用错场景,卡顿就躲不掉
很多人一上来就写 animation,哪怕只是 hover 下的按钮颜色渐变。但 transition 更轻量、触发更可控,浏览器也更容易优化。只有当需要多关键帧、循环、延迟或复杂时序时,才该切到 animation。
-
transition适合状态切换(如展开/收起、悬停反馈),依赖属性变化自动触发 -
animation适合定义好的播放行为(如加载骨架、图标旋转、路径描边),需显式animation-name或内联@keyframes - 滥用
animation: spin 2s infinite转圈,却忘了给transform加will-change: transform或用transform: rotateZ(0)触发 GPU 层,结果在低端安卓上掉帧
@keyframes 里别写 layout 触发属性
写 @keyframes slide { to { left: 100px; top: 50px; } } 看似直觉,实则灾难:每次计算都触发重排(reflow)。浏览器得反复测量元素位置、影响父容器、波及兄弟节点。
- 只用
transform(translate/scale/rotate)和opacity—— 这俩是合成层友好属性,走 GPU,不重排不重绘 - 避免在动画中修改
width、height、margin、padding、left、top等会触发布局的属性 - 如果必须“看起来”在改变尺寸,用
transform: scale()模拟,再配合transform-origin控制缩放锚点
animation-timing-function 不是调速器,是节奏控制器
ease-in-out 不等于“慢进慢出”,它描述的是贝塞尔曲线的控制点位置,直接影响人眼感知的加速度感。默认的 cubic-bezier(0.25, 0.1, 0.25, 1.0) 在长距离位移中容易显得“头重脚轻”。
立即学习“前端免费学习笔记(深入)”;
- 短交互(如按钮点击反馈)用
ease-out或cubic-bezier(0.2, 0.8, 0.4, 1),干净利落 - 长位移(如模态框入场)推荐
cubic-bezier(0.34, 1.56, 0.64, 1)(即 “smooth” 变体),有轻微回弹感,比纯ease-in-out更自然 - 慎用
step-start/step-end:它们不插值,适合翻页、打字机等逐帧效果,但用错地方会显得机械僵硬
JavaScript 控制 CSS 动画时,别直接 toggle class
直接 el.classList.toggle('is-animating') 后,浏览器可能因样式未及时生效而跳过第一帧,或者因类名移除太快导致动画中断。尤其在快速连续触发时(比如滚动中呼出浮层),问题更明显。
- 用
getComputedStyle(el).animationName或监听animationend事件来确认动画是否真正结束,再操作 DOM - 需要 JS 中断动画?优先用
el.style.animationPlayState = 'paused',而不是删 class —— 后者会重置整个动画状态 - 想从 JS 启动一个一次性动画?改用
el.animate()(Web Animations API),它返回 Animation 对象,可精确控制时间、暂停、反转,且不依赖 CSS 类
真正难的从来不是写出 100 个动画,而是判断哪个动画不该存在——比如那个为了“高级感”加在每张卡片上的微晃动,既无信息价值,又悄悄吃掉 3fps。