css @keyframes 最稳,适合90%简单动画;复杂控制用 element.animate();requestanimationframe 仅用于逐帧计算;svg 动画应弃用 标签,改用 css 或 element.animate()。

用 CSS @keyframes 做网页动画最稳
浏览器原生支持、性能好、写法轻量,90% 的简单交互动画(比如按钮悬停、加载指示器、卡片入场)直接用它就够了。别一上来就翻 React 动画库或 requestAnimationFrame 手写循环。
常见错误是把动画逻辑塞进 JS 里反复操作 style.transform,结果卡顿还难维护。CSS 动画由浏览器合成线程处理,GPU 加速更可靠。
实操建议:
- 动画属性优先用
transform和opacity—— 它们不触发重排(layout),只走重绘或合成 - 避免对
width、height、left、top等触发重排的属性做动画 - 加
will-change: transform可提前提示浏览器优化,但别滥用,尤其别写在大量元素上 - 示例:
@keyframes slideIn { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); } } .element { animation: slideIn 0.3s ease-out forwards; }
JS 控制动画节奏得靠 element.animate()
需要动态控制播放、暂停、反向、调整时长,或者做链式动画时,element.animate() 是现代浏览器(Chrome 36+、Firefox 48+、Safari 12.1+)的首选,比手动改 class 或 style 更精准。
立即学习“前端免费学习笔记(深入)”;
它返回一个 Animation 对象,能监听状态、绑定事件、实时修改时间轴 —— 这是纯 CSS 动画做不到的。
容易踩的坑:
-
element.animate()不兼容 IE,连 Edge Legacy 都不支持,必须有降级方案(比如 fallback 到 CSS 类切换) - 动画参数是数组:第一个是关键帧对象数组,第二个是配置对象(
duration、easing、fill等),别把它们写反 - 没设
fill: 'forwards',动画结束后元素会“弹回”初始状态 - 示例:
const anim = el.animate( [{ opacity: 0 }, { opacity: 1 }], { duration: 300, easing: 'ease-out', fill: 'forwards' } ); anim.pause(); // 可随时控制
复杂交互动画慎用 requestAnimationFrame
真要逐帧计算(比如拖拽跟随、物理模拟、滚动视差联动),requestAnimationFrame 是底层选择,但它不是“更高级”,而是“更难控”。多数人高估了需求,低估了维护成本。
性能陷阱明显:没节流、没取消旧帧、没做 visibility 判断,页面切到后台还在狂跑,耗电又掉帧。
实操要点:
- 每次调用前先用
cancelAnimationFrame清掉上一次 ID,避免叠加 - 用
document.hidden监听页面可见性,在后台自动暂停 - 别在 rAF 里直接改
style.left/top,坚持用transform - 如果只是想让某个动作“顺滑跟手”,先试试
scroll-behavior: smooth或will-change+ CSS 过渡
SVG 动画别碰 <animate></animate> 标签
HTML5 里 SVG 原生支持 <animate></animate>、<set></set> 等标签,但它们早已被主流放弃:不支持 CSS 变量、无法用 JS 精确控制、调试困难、兼容性差(尤其 Safari 对某些属性支持不全)。
现在标准做法是把 SVG 当 DOM 元素对待,用 CSS @keyframes 或 element.animate() 操作它的 transform、stroke-dasharray 等属性。
特别注意:
- SVG 内联样式(
style="...")会覆盖外部 CSS 动画,记得删掉或用!important覆盖(不推荐,优先改结构) - 路径描边动画(
stroke-dasharray+stroke-dashoffset)必须先用 JS 算出路径总长度(getTotalLength()),不然动画会错位 - 不要给
<g></g>或<path></path>直接加animation,确保目标元素有明确尺寸和坐标系(比如加viewBox)
easing 曲线,却没发现用户根本注意不到那个过渡。










