必须用 html 的 width/height 属性或 js 的 canvas.width/canvas.height 设置缓冲区尺寸,否则绘图会拉伸失真;css 仅控制显示尺寸,不改变像素缓冲区,需同步适配 devicepixelratio 并重绘。

必须用 width 属性设,不能只靠 CSS —— 否则画布缓冲区还是默认的 300×150,所有绘图都会被拉伸失真,坐标映射全错。
canvas.width 是像素缓冲区大小,不是显示尺寸
width 和 height 是 HTML 属性,直接决定内存中位图的像素数量。比如 <canvas width="800" height="600"></canvas> 就分配了 800×600 像素的绘图空间,ctx.fillRect(0,0,800,600) 才能铺满整个区域。
- 没写
width/height→ 浏览器硬编码为300×150,哪怕 CSS 设成 100% 宽高也一样 -
canvas.style.width = "800px"→ 只缩放显示框,不改缓冲区,图形糊、圆变椭、鼠标点不准 -
canvas.width = 800→ 重置缓冲区,清空画布,但这是正常行为,不是 bug
JS 动态设置 width 的正确姿势
响应式或运行时调整必须用 JS 赋值给 canvas.width,同时要重绘内容(因为赋值会清空画布)。
- 先读真实布局尺寸:
const w = canvas.clientWidth,再乘window.devicePixelRatio补高清屏 - 赋值后立刻重绘:
canvas.width = w * dpr→draw()必须跟上,否则画面空白 - 别写
canvas.width = "800px"或800.5,只接受整数,否则回退到默认300×150 - 监听
resize不够,得配合ResizeObserver或手动触发重设逻辑
常见踩坑:CSS 和 HTML width/height 混用
写成 <canvas width="400" height="300" style="width:800px;height:600px"></canvas> 看似“放大”,实则是把 400×300 的图强行拉伸两倍 —— 圆变椭、文字发虚、isPointInPath() 失效、导出 PNG 尺寸不对。
- 如果要用 CSS 控制显示尺寸,必须同步更新
canvas.width/canvas.height匹配实际像素需求 - 高 DPI 设备上尤其明显:
window.devicePixelRatio是 2 时,clientWidth=400对应真实缓冲区应是800 - 最隐蔽的坑:某处 CSS 覆盖了
canvas的width显示,但 JS 没同步更新属性,失真静默存在,直到你画斜线或做点击检测才暴露
真正难的不是设宽高,而是让缓冲区像素数、CSS 显示尺寸、设备像素比、鼠标坐标换算这四者始终对齐——少一个环节,模糊和错位就藏不住了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











