移动端Canvas需协同设置width/height、style.width/height、devicePixelRatio、touch-action等属性:必须按DPR重设canvas.width/height并配合ctx.scale(dpr,dpr),设touch-action:none且preventDefault(),图片跨域需crossOrigin="anonymous"与服务端CORS头匹配,clearRect慎用可改fillRect。

canvas 在移动端不是“写完就能跑”,关键属性不设对,轻则模糊卡顿,重则触摸失灵、跨域报错、动画掉帧。核心不在功能有没有,而在 width/height、style.width/style.height、devicePixelRatio、touch-action 这几项是否协同生效。
canvas.width 和 canvas.height 必须按 DPR 重设,不能只靠 CSS 缩放
常见错误是只写 canvas.style.width = "300px"; canvas.style.height = "150px";,却没动 DOM 属性 width 和 height。结果就是:CSS 显示 300×150,但 Canvas 内部缓冲区仍是默认 300×150 像素(即 1×DPR),在 iPhone 上实际只有 1/4 物理像素被填充,必然模糊。
- 必须读取
window.devicePixelRatio,再乘到canvas.width和canvas.height上(这是真实绘图分辨率) -
canvas.style.width和canvas.style.height只控制显示尺寸,保持为逻辑像素值(如"300px") - 紧接着调用
ctx.scale(dpr, dpr),让所有绘图坐标仍按逻辑尺寸写,不用改业务代码 - 别用
transform: scale()或zoom拉伸 canvas 元素——二次插值会让边缘更糊
touch-action: none 是 iOS Safari 触摸响应的前提
Canvas 默认不响应 touchstart,不是监听漏了,是浏览器把它当“非交互区域”处理了。加 tabindex="0" 或 cursor: pointer 都无效。
- 必须在 canvas 元素上设置内联样式或 CSS 类:
touch-action: none - 同时在
touchstart和touchmove回调里调用event.preventDefault(),否则双击会缩放、滑动会滚动 - 如果只监听
touchstart却没preventDefault(),iOS 上快速点击可能直接触发页面缩放,签名或拖拽类功能当场失效 - 安卓部分 WebView 对
touch-action支持弱,可额外加user-select: none防误选
drawImage 跨域失败?crossOrigin 属性和服务器头必须配齐
报错 Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The image argument is a canvas whose origin-clean flag is false. ——这不是 canvas 问题,是图片跨域策略断了。
立即学习“前端免费学习笔记(深入)”;
-
<img>标签必须带crossOrigin="anonymous"(注意:值只能是"anonymous",空字符串或"use-credentials"在多数 CDN 场景下会失败) - 图片资源所在服务端必须返回
Access-Control-Allow-Origin: *(或指定域名),且不能带Access-Control-Allow-Credentials: true(除非你明确需要 cookie) - 用
img.crossOrigin = "anonymous"动态设置时,必须在设置src之前完成,否则缓存中已加载的图片不会重新发起带 CORS 的请求 - 本地开发时若用
file://协议,CORS 机制不生效,务必起本地服务(如python3 -m http.server)测试
clearRect 性能陷阱:安卓低端机慎用全量清屏
每帧都调 ctx.clearRect(0, 0, width, height) 在 Mali GPU 的安卓设备上极易引发内存带宽瓶颈,动画直接卡在 20fps 以下。
- 优先用
ctx.fillStyle = "#fff"; ctx.fillRect(0, 0, width, height)替代clearRect,部分 WebView 对 fillRect 优化更好 - 静态背景和动态内容拆成两个
canvas叠放,动的那一层只clearRect(x, y, w, h)局部擦除 - 避免在
touchmove中直接重绘,先节流(requestAnimationFrame),再批量更新 -
shadowBlur和globalAlpha会显著增加合成开销,低端机上建议关闭或降级为纯色描边
最易被忽略的是:这些属性之间存在强依赖关系——touch-action: none 不设,preventDefault() 就白写;devicePixelRatio 不读,ctx.scale() 就失去意义;crossOrigin 和服务端头缺一不可。它们不是独立开关,而是一组必须同步生效的兼容锚点。



















