requestAnimationFrame 比 setTimeout 更稳,因其同步屏幕刷新、自动暂停、避免掉帧;CSS @keyframes 适合声明式动效;Canvas 需注意缩放、清除与绘制顺序;Web Animations API 提供动态控制能力。

用 requestAnimationFrame 做动画比 setTimeout 更稳
浏览器渲染帧率不等于 JS 执行节奏,硬塞 setTimeout 容易掉帧、卡顿、耗电。真正同步屏幕刷新的只有 requestAnimationFrame。
常见错误现象:setTimeout(..., 16) 看似想模拟 60fps,但实际执行时间不可控,叠加样式重排/重绘后极易错失帧;动画中途切后台再回来,setTimeout 还在跑,而 requestAnimationFrame 自动暂停。
- 只在需要持续更新视觉状态时调用,比如滚动视差、粒子运动、进度条填充
- 每次回调里做完计算 + 修改
style或transform,别触发 layout(如读offsetTop) - 退出动画时必须手动调用
cancelAnimationFrame,否则内存泄漏
CSS @keyframes + animation 属性适合声明式动效
按钮悬停缩放、加载转圈、淡入弹出这类有明确起止和路径的动效,优先写 CSS,不碰 JS。
使用场景:不需要运行时动态改动画参数(如速度、方向),也不依赖用户交互中间态(比如拖拽中实时反馈)。
立即学习“前端免费学习笔记(深入)”;
-
animation-timing-function别全用ease,试试cubic-bezier(0.2, 0.8, 0.4, 1)更自然 - 避免对
width/height动画,改用transform: scale()或opacity,触发 GPU 加速 - 加
animation-fill-mode: forwards,不然动画结束元素会“弹回”初始状态
Canvas 动画要管好 clearRect 和绘制顺序
画布不会自动擦除上一帧,漏掉 clearRect 就会糊成一片;但清得太狠(比如清整个画布)又影响性能。
自动隐藏的QQ在线客服代码是一款基于jQuery实现的默认展开可自动隐藏的QQ在线客服代码,界面非常简洁,此款JS代码特效可按客服功能放置不同的客服QQ号码,鼠标移上去即展开客服信息,移走自动隐藏,如果需要修改其中客服信息,修改service.js文件即可。
容易踩的坑:在高 DPI 屏幕下直接用 canvas.width/canvas.height 设置尺寸,导致模糊;或在 requestAnimationFrame 回调里反复 getContext('2d')。
- 初始化时按设备像素比缩放 canvas:设
canvas.style.width为逻辑宽高,再按window.devicePixelRatio放大canvas.width/canvas.height - 只清除需要重绘的矩形区域,比如粒子系统里只清旧位置+新位置的并集
- 先画背景(静态),再画中间层(缓变动),最后画前景(高频变),减少重复绘制
Web Animations API(element.animate())适合 JS 控制动效细节
当你要在运行时动态生成动画、链式播放、暂停/反转/调整播放速率,element.animate() 比纯 CSS 更灵活,也比手写 requestAnimationFrame 简洁。
兼容性注意:IE 全系不支持,Safari 13.1+ 才支持完整功能;部分属性如 clip-path 动画仍需加厂商前缀或 fallback。
- 动画对象返回值有
onfinish回调和playState属性,可做状态同步 - 多个动画同时作用于同一属性时,后启动的会覆盖前面的,别指望它们自动合并
- 用
timeline选项可绑定到文档滚动进度,实现 scroll-driven 动画(目前仅 Chromium 支持)
真正难的不是写出动效,是判断该不该动、动多少、什么时候停。比如列表滚动中每个 item 都加入场动画,用户根本来不及感知,还拖慢首屏;又比如深色模式切换时硬加 300ms 淡出,反而打断操作流。这些得看场景,不是套代码能解决的。









