canvas绘图分辨率仅由html的width/height属性决定,与css的style.width/style.height无关;需用resizeobserver监听父元素、同步宽高并适配dpr,同时flex-item须设min-width:0/min-height:0。

canvas.width/height 和 style.width/style.height 是两套系统
Canvas 的绘图分辨率只认 width 和 height 这两个 HTML 属性,不是 CSS 的 style.width 或 style.height。Flex 容器可以拉伸 canvas 的布局盒(比如用 flex: 1 把它撑到 800×600),但只要 canvas.width 还是默认的 300、canvas.height 还是 150,浏览器就只能把这 300×150 的像素缓冲区强行“拉伸”进显示区域——结果就是模糊、坐标错位、鼠标点不中。
常见错误现象包括:
-
getBoundingClientRect().width返回 800,但canvas.width仍是 300 - 画一条从
(0,0)到(250,250)的线,实际只出现在左上角一小块 - 鼠标
clientX/clientY换算成 canvas 坐标后,和ctx.fillRect()落点完全对不上
ResizeObserver 必须监听 parentElement,不是 canvas 自身
Canvas 元素自身尺寸不变时,ResizeObserver 不会触发;真正变化的是它所在的 flex-item(比如侧边栏收起、响应式断点切换)。所以必须观察 canvas.parentElement,而不是 canvas。
监听后要做的事:
- 用
element.getBoundingClientRect()读取当前渲染宽高 - 把该宽高赋给
canvas.width和canvas.height,注意必须是整数,推荐Math.floor(rect.width)和Math.floor(rect.height) - 显式设置
canvas.style.width = "100%"和canvas.style.height = "100%",否则父 flex-item 可能因尺寸未收敛而抖动 - 重绘:调用
ctx.clearRect()和你的绘制逻辑
高 DPI 屏幕下必须适配 devicePixelRatio
在 Retina 或 4K 屏上,仅同步 width/height 到 clientWidth/clientHeight 仍会模糊或右下偏移。因为浏览器把 width 当作物理像素数,而 CSS 尺寸是逻辑像素。
正确做法是:
- 读取
window.devicePixelRatio,别硬写2或3 - 设
canvas.width = Math.floor(canvas.offsetWidth * dpr),同理设height - 立即调用
ctx.scale(dpr, dpr),让后续所有绘图坐标仍按 CSS 像素书写 - 每次重设
width/height都会重置上下文,scale必须重做
flex-item 上漏掉 min-width: 0 会导致尺寸卡死
如果 canvas 所在的 flex-item 没设 min-width: 0,它会被浏览器默认的 min-width: auto 锁住宽度——哪怕你写了 flex: 1 或 width: 100%,它也可能拒绝收缩,导致 canvas 拿不到预期尺寸。
验证方法:打开开发者工具,查该 flex-item 的 computed min-width,若显示 auto,就是它了。必须显式加:
-
min-width: 0(水平方向) -
min-height: 0(垂直方向,尤其当 flex-direction 是 column 时)
这个值不会自动继承,也不能靠父容器“传导”,每个 flex-item 都得自己加。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











