canvas.width/height 控制位图缓冲区大小,决定像素数量、坐标映射、线宽渲染精度、路径检测准确性及图像数据量;仅用CSS设置尺寸会导致拉伸失真,高DPI下更严重;响应式需同步更新缓冲区、显示尺寸和缩放比例。

canvas.width/height 属性控制的是位图缓冲区大小
它直接决定画布内部有多少像素、坐标系如何映射、ctx.lineWidth = 1 实际渲染多粗、isPointInPath() 判断是否准确,甚至 getImageData() 返回多少数据。比如 <canvas width="800" height="600"></canvas> 就是分配一块 800×600 的内存区域用于绘图——这不是“显示大小”,而是“绘图精度的底线”。
常见错误现象包括:ctx.lineTo(100, 100) 画出来不是正方形对角线、圆变成椭圆、文字边缘发虚、鼠标点击坐标偏移几十像素。这些都不是 bug,而是缓冲区尺寸和显示尺寸不匹配的必然结果。
仅用 CSS 设置 canvas 尺寸等于强制拉伸一张小图
canvas.style.width 和 canvas.style.height 只改变 DOM 元素的显示框大小,不碰底层位图。浏览器只能对现有像素做插值缩放——就像把一张 300×150 的 JPEG 拉到全屏,再怎么调锐化也救不回细节。
高 DPI 设备下更致命:window.devicePixelRatio === 2 时,若只设 style="width:400px;height:300px",实际物理像素仍只有 200×150,却要填满 400×300 显示区域,双线性插值一上,线条毛边、圆形变形、触控错位全来了。
立即学习“前端免费学习笔记(深入)”;
- 写
canvas.style.width = "400px"不会清空画布,但会导致所有绘图失真 - 写
canvas.width = 400会清空画布并重建缓冲区,这是预期行为 - 两者混用(比如 HTML 里设了
width="400",CSS 又设width: 800px)会静默拉伸,直到你画斜线或做精确交互才暴露问题
响应式重设 canvas 必须同步更新三个值
监听 resize 或用 ResizeObserver 不够,关键是要同步更新缓冲区、显示尺寸和坐标缩放比例:
先读取真实布局尺寸:const w = canvas.clientWidth; const h = canvas.clientHeight;
再按设备像素比设置缓冲区:canvas.width = w * window.devicePixelRatio; canvas.height = h * window.devicePixelRatio;
最后缩放显示层:canvas.style.width = w + "px"; canvas.style.height = h + "px";
做完这三步后,别忘了重绘内容——因为 canvas.width = ... 会清空画布。
容易被忽略的静默失效点
哪怕你 JS 初始化时写对了 canvas.width 和 canvas.height,只要后续某处 CSS(比如全局 canvas { max-width: 100%; })偷偷覆盖了显示尺寸,而没同步更新 HTML 属性或 JS 值,失真就一直安静地埋着。
它不会报错,也不会警告,直到你贴一张 PNG、画一条 45° 线、或者做精确的 getBoundingClientRect() + clientX/clientY 换算时,坐标突然差出 20px——那时你得倒查整个样式链和 JS 初始化顺序。



















