clearRect仅擦除像素而不重置绘图状态,resetCanvas(重设width)才能彻底重置所有状态;fillRect填透明色是覆盖而非清空,依赖合成模式且不改变状态。
clearRect 是最常用也最容易出错的清空方式
它只擦像素,不重置状态——这是绝大多数“清完了但画出来不对”的根源。比如你之前设过 ctx.globalalpha = 0.5 或 ctx.transform(2, 0, 0, 2, 0, 0),clearrect 完全不管这些,后续绘图照样变淡、放大、偏移。
- 必须用
ctx.clearRect(0, 0, canvas.width, canvas.height),别用 CSS 尺寸(如canvas.style.width)算出来的值,否则清不全 - 清空前不用
beginPath(),它对clearRect没影响 - 如果画布有缩放或旋转,
clearRect仍按原始坐标系清除,不会“跟着转” - 它不能清除裁剪区域外的内容,但也不会受当前裁剪路径限制——
clearRect总是全局生效
resetCanvas(重设 width)能真正重置一切,但代价明确
给 canvas.width 赋值(哪怕赋成自己),会强制丢弃旧缓冲区、重建位图,并把所有上下文状态打回出厂设置:变换归零、样式复位、裁剪失效、路径清空。这是唯一能“彻底重置”的办法。
- 适合初始化、切换模式、加载新场景等非高频操作
- 千万别在
requestAnimationFrame循环里写canvas.width = canvas.width,卡顿立竿见影 - 如果 canvas 同时绑了 WebGL 上下文,这一步会让
gl失效,得手动重建 - 推荐封装成函数:
function resetCanvas(canvas) { const w = canvas.width; const h = canvas.height; canvas.width = w; canvas.height = h; }
fillRect 填透明色不是“清空”,而是“覆盖”
用 ctx.fillStyle = 'rgba(0,0,0,0)' 再 fillRect,视觉上像清空了,但它依赖合成模式,且不改变任何状态。一旦你之前设过 globalCompositeOperation = 'destination-out',这招就变成橡皮擦,甚至可能把背景也挖掉。
- 仅适用于需要保留当前绘图状态(比如还在做连续笔迹动画),又想视觉归零的场景
- 必须确保
globalCompositeOperation是默认的'source-over',否则行为不可控 - 填纯黑或纯白也能“遮盖”,但会破坏透明度信息,不适合图层叠加类应用
- 比
clearRect稍慢一点,因为要走填充流水线,而非直接内存置零
清空后记得检查 globalCompositeOperation 和 save/restore 链
很多“清完还留痕”“画线颜色不对”问题,根本不是清不干净,而是清完没恢复关键状态。尤其当你用过 save() 却忘了 restore(),或者中途改过合成模式,清空操作本身反而成了状态污染的起点。
- 高频绘图循环中,建议清空前
ctx.save(),清空后ctx.restore(),一进一出保安全 - 如果用了
destination-out做橡皮擦,清空后务必手动设回'source-over' -
save()/restore()不解决重设width引起的状态丢失,那是另一套机制 - 没有万能清空方案——选
clearRect就得自己管状态,选重设width就得扛性能代价











