Canvas在iOS Safari中需设touch-action: none并preventDefault()防缩放;Retina屏须按devicePixelRatio缩放绘图坐标系;安卓卡顿应避免全量clearRect、拆分canvas层、慎用阴影透明度;跨域图片需img加crossOrigin="anonymous"且服务端配CORS头。

Canvas 在 iOS Safari 上不响应触摸事件
Canvas 默认不会触发 touchstart、touchmove 等事件,尤其在 iOS Safari 中——不是代码写错了,是浏览器默认把 Canvas 当作“非交互区域”处理了。
- 给
<canvas>加style="cursor: pointer;"或tabindex="0"都没用,关键得加touch-action: none - 如果只监听
touchstart但没阻止默认行为,快速点击可能触发双击缩放或滚动,记得在事件回调里调用event.preventDefault() - 别在
touchmove里直接做重绘,先用requestAnimationFrame节流,否则 iOS 上容易卡顿甚至掉帧
Canvas 绘图模糊、像素不对齐(尤其是 Retina 屏)
不是画布“质量差”,是没适配设备像素比(window.devicePixelRatio)。iOS 和高分屏安卓机默认用 2x 或 3x 物理像素渲染 1x CSS 像素,直接按 CSS 尺寸画图必然模糊。
- 创建 canvas 时,先读
devicePixelRatio,再手动设置canvas.width和canvas.height为 CSS 尺寸 × ratio - 然后用
ctx.scale(ratio, ratio)缩放绘图坐标系,这样所有ctx.fillRect(0, 0, 100, 100)仍写逻辑尺寸,不用改业务代码 - 别用 CSS 的
transform: scale()拉伸 canvas 元素,会二次采样,糊得更明显
Canvas 动画在低端安卓机卡顿严重
不是 JS 性能差,而是频繁调用 clearRect() + 全量重绘,在 Mali GPU 上触发大量内存带宽压力。尤其带阴影、渐变、多图层叠加时更明显。
- 避免每帧都
ctx.clearRect(0, 0, width, height);改用ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, width, height),对部分安卓 WebView 更友好 - 静态背景和动态元素拆成两个 canvas 叠放,动的那层只清局部区域(
clearRect(x, y, w, h)),不动的完全不碰 - 慎用
shadowBlur和globalAlpha,它们会让合成路径变复杂,低端机上直接掉到 20fps 以下
drawImage() 加载网络图片跨域失败
图片从 CDN 或其他域名加载时,ctx.drawImage(img, ...) 会报 Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The image argument is a canvas whose origin-clean flag is false. ——不是 canvas 问题,是图片没声明允许跨域。
立即学习“前端免费学习笔记(深入)”;
- 给
<img>标签加crossOrigin="anonymous"属性(注意:值必须是"anonymous",不能是空字符串或"*") - 服务端图片响应头需包含
Access-Control-Allow-Origin: *,否则即使加了属性也无效 - 用
URL.createObjectURL(blob)加载本地文件时,无需跨域处理;但转 base64 后赋值给img.src也不触发跨域限制
最常被忽略的是:iOS Safari 对 canvas.toDataURL() 的尺寸限制(单边超 5000px 可能返回空字符串),还有安卓某些定制系统 Webview 里 getImageData() 会静默失败——真要读像素,得先兜底检测 ctx.getImageData(0,0,1,1) 是否抛错。











