Canvas 的 width/height 必须用 HTML 属性设置而非 CSS,因绘图缓冲区分辨率由 HTML 属性决定;getContext("2d") 是唯一且不可重复获取的绘图入口;需手动清屏重绘,无自动更新;初始化须嵌入完整游戏循环并适配设备像素比。

Canvas 元素的 width/height 必须用 HTML 属性写死
Canvas 的像素尺寸不是靠 CSS 控制的,style="width:800px;height:600px" 只会拉伸位图,导致模糊、坐标偏移、触控错位。真正决定绘图缓冲区分辨率的是 width 和 height 这两个 HTML 属性。
常见错误现象:高清屏(window.devicePixelRatio > 1)下线条发虚、小球移动一卡一卡、鼠标点击位置和实际绘制位置偏差几十像素——八成是这里没设对。
- ✅ 正确:
<canvas id="game" width="800" height="600"></canvas> - ❌ 错误:
<canvas id="game" style="width:800px;height:600px"></canvas> - ⚠️ 补救:若需适配高清屏,应在 JS 中按设备像素比重设属性,例如:
canvas.width = 800 * window.devicePixelRatio,再手动缩放 canvas.style
getContext("2d") 是唯一绘图入口,且不可重复获取不同上下文
getContext("2d") 返回的是 CanvasRenderingContext2D 实例,所有绘图操作(fillRect、arc、drawImage)都依赖它。同一个 <canvas> 元素一旦调用过 getContext("2d"),就不能再调用 getContext("webgl") —— 浏览器会返回 null。
容易踩的坑:在调试时反复执行 canvas.getContext("2d") 没问题,但若误写成 getContext("2D")(大小写敏感)或 getContext("2d ")(带空格),会静默返回 null,后续所有绘图调用都不报错却无效果。
立即学习“前端免费学习笔记(深入)”;
- 务必检查返回值是否为真值:
const ctx = canvas.getContext("2d"); if (!ctx) throw new Error("2D context not supported"); - 不要在每次动画帧里重复调用
getContext,缓存一次即可 - WebGL 上下文需单独用
getContext("webgl"),与 2D 不兼容
初始化后必须手动清空并重绘,没有“自动更新”这回事
Canvas 是位图,不是 DOM。你画完一个矩形,它就固化成一堆像素;想移动它,不能改 x 属性,只能先 clearRect 清掉旧位置,再在新位置重画——这是高性能的前提,也是最容易被初学者忽略的机制。
典型错误:只画不擦,导致上一帧残留、拖影严重;或用 ctx.clearRect(0, 0, canvas.width, canvas.height) 清全屏但未考虑缩放,结果清不干净。
- 清屏范围必须用 canvas 的真实像素尺寸(即
canvas.width/canvas.height,不是 CSS 尺寸) - 高频渲染(如 60fps 游戏)建议用
requestAnimationFrame驱动,避免setTimeout时间漂移 - 局部重绘更省资源:比如只清角色区域,而非整屏,但需自行管理脏矩形(dirty rect)逻辑
Canvas 初始化要配合游戏循环结构,不能只做一次
初始化不只是“拿到 ctx”,而是要嵌入整个游戏生命周期:准备资源 → 启动循环 → 持续更新 + 渲染。很多性能问题其实出在初始化之后的衔接断层上。
比如:图像资源(new Image())未等 onload 就开始绘制,导致黑块;或音频上下文未在用户手势后激活,导致音效静音。
- 把
initGrid()、loadAssets()、setupInputHandlers()等函数放在初始化阶段统一调用 - 确保
requestAnimationFrame(loop)在资源加载完成后才启动,否则首帧可能空白或错乱 - 监听
resize事件时,不仅要改 canvas.style,还要重设canvas.width/height并重置绘图状态(如ctx.resetTransform())
Canvas 初始化看着就几行代码,但宽高属性、上下文获取、清屏机制、循环衔接这四点,任意一个松动都会让后续所有优化失效。尤其在多设备、多分辨率、多交互场景下,漏掉设备像素比处理或清屏尺寸匹配,问题往往到上线才暴露。



















