Canvas全屏动画需通过每帧清屏、更新、重绘闭环实现,核心是控制帧节奏、减少状态切换与无效重绘;初始化须按DPR缩放并监听resize防抖;动画必须用requestAnimationFrame递归驱动,每帧显式重置绘图状态,结合离屏缓存、批量绘制和deltaTime优化性能。

Canvas 全屏动画不是“画完就动”,而是靠每帧清屏、更新、重绘三步闭环驱动的位图动画。核心在于控制好帧节奏、减少状态切换、避免无效重绘,否则再酷的特效也会卡顿或发虚。
全屏 Canvas 初始化与响应式适配
全屏不是简单设 width/height=100%,必须兼顾 CSS 显示尺寸和真实像素密度:
- HTML 中只写
<canvas id="bg"></canvas>,不设 width/height 属性 - CSS 设置
#bg { width: 100vw; height: 100vh; display: block; } - JS 初始化时按设备像素比缩放 canvas 内部尺寸:
const dpr = window.devicePixelRatio || 1;<br> canvas.width = canvas.clientWidth * dpr;<br> canvas.height = canvas.clientHeight * dpr;<br> ctx.scale(dpr, dpr); - 监听
resize事件重新设置尺寸(注意防抖,避免频繁重置)
动画主循环:requestAnimationFrame 是唯一正解
别用 setInterval 或 setTimeout——它们无法对齐屏幕刷新,后台运行也不暂停,极易掉帧或积压。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 主函数必须递归调用自身:
function animate() {<br> ctx.clearRect(0, 0, canvas.width, canvas.height);<br> update(); // 位置、颜色、状态等逻辑更新<br> render(); // 绘制所有内容<br> requestAnimationFrame(animate);<br> } - 启动时存下 ID:
let animId = requestAnimationFrame(animate); - 停用时务必清理:
cancelAnimationFrame(animId);,防止内存泄漏 - 若需暂停(如页面切到后台),可加 visibilitychange 监听自动启停
清屏与状态管理:残影和模糊的根源
clearRect 只擦像素,不重置绘图状态。漏重置 fillStyle、globalAlpha、lineWidth、transform 等,就会逐帧叠加变糊。
立即学习“前端免费学习笔记(深入)”;
- 每帧开头 clearRect 后,显式重置关键状态:
ctx.globalAlpha = 1;<br> ctx.setTransform(1, 0, 0, 1, 0, 0); // 重置变换矩阵<br> ctx.strokeStyle = '#000'; // 避免继承上一帧颜色 - 慎用 save()/restore()——开销大;局部重绘优先用
clearRect(x, y, w, h)擦指定区域 - 禁止用
canvas.width = canvas.width清屏——它会重置全部上下文,后续绘图可能失效
性能优化:从“能跑”到“丝滑”的关键动作
Canvas 快是因为绕过 DOM,但 JS 驱动不当反而比 div 还慢。重点在减少 GPU 状态切换和无效绘制。
- 批量绘制同类图形:先设一次
ctx.fillStyle,再循环 draw,别每画一个都设颜色 - 静态内容(如背景网格、标题文字)用离屏 canvas 缓存,只在变更时重绘一次
- 粒子、线条等大量对象,用 Float32Array 存坐标,比普通数组访问快 2–3 倍
- 加入 deltaTime 校准运动逻辑,让动画速度与设备无关:
let lastTime = 0;<br> function animate(timestamp) {<br> const dt = timestamp - lastTime;<br> lastTime = timestamp;<br> x += vx * (dt / 16); // 以 60fps 为基准归一化<br> // ...<br> }


















