Canvas图像位置跨设备差异的根源是设备像素比、CSS显示尺寸与实际像素尺寸未同步,需动态调整canvas.width/height并配合ctx.scale()和事件坐标归一化处理。
HTML5中canvas绘图坐标系本身没有设备差异
真正导致平板和电脑上图像位置“看起来不同”的,不是canvas坐标系统变了,而是设备像素比(window.devicePixelRatio)、视口缩放、CSS渲染尺寸与画布实际像素尺寸的错位。比如你在canvas上用ctx.fillRect(10, 10, 20, 20)画一个方块,逻辑坐标永远是(10,10),但最终在屏幕上占多少物理像素,取决于canvas.width/canvas.height是否匹配当前显示所需的像素密度。
canvas.width和canvas.style.width不一致是主因
常见错误是只设置canvas.style.width = "100%"或固定CSS宽高,却不同步调整canvas.width和canvas.height属性——这会导致浏览器拉伸画布,所有绘制内容被模糊、偏移、比例失真。
-
canvas.width和canvas.height是画布的**渲染像素数**(即内部绘图缓冲区大小) -
canvas.style.width和.style.height是画布在页面上的**CSS显示尺寸**(单位可以是px、%、rem等) - 当二者不等价(如
canvas.width=800但style.width="400px"),浏览器会按2×缩放渲染,鼠标事件坐标、图像定位全都会偏
正确做法是动态同步:
function resizeCanvas() {
const canvas = document.getElementById("myCanvas");
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
canvas.style.width = rect.width + "px";
canvas.style.height = rect.height + "px";
const ctx = canvas.getContext("2d");
ctx.scale(dpr, dpr); // 确保绘图逻辑坐标不变
}
触摸坐标 vs 鼠标坐标的归一化处理
平板用touchstart/touchmove,电脑用mousedown/mousemove,但它们返回的clientX/clientY都是相对于视口的CSS像素,而canvas绘图坐标基于的是自身width/height(含DPR)。不做转换,点击位置就会偏差。