canvas.width/height决定绘图缓冲区实际像素尺寸,影响精度与渲染效果;仅用CSS缩放会导致拉伸模糊,响应式需结合devicePixelRatio动态重设并用ctx.scale补偿。

canvas.width/height 是画布缓冲区尺寸,不是样式
直接在 <canvas> 标签里写 width="800" 和 height="600",是在告诉浏览器:“分配一块 800×600 像素的位图内存”,所有绘图坐标、线条粗细、文字渲染、getImageData() 返回的数据量都基于这个尺寸。它不是“看起来多大”,而是“实际能画多精细”。
常见错误现象:ctx.lineWidth = 1 画出来像 2 像素宽;圆形边缘发虚;isPointInPath() 判断失效;导出 PNG 尺寸不对——这些几乎全是缓冲区尺寸没设对导致的。
如果只用 CSS 设置 style="width: 800px; height: 600px",而没设 HTML 属性或 JS 赋值,canvas 实际缓冲区仍是默认的 300×150,内容被强行拉伸,插值模糊不可避免。
style.width/style.height 只是 DOM 元素缩放,不改绘图精度
CSS 的 width 和 height 控制的是 canvas 这个 DOM 元素在页面上的显示框大小,和内部绘图表面完全无关。就像把一张小照片放进大相框——相框变大了,照片还是那张,只是被拉伸了。
立即学习“前端免费学习笔记(深入)”;
容易踩的坑:
- 用
canvas.style.width = "100%"后忘记同步重设canvas.width和canvas.height - 在响应式布局中只监听
window.resize,但没考虑devicePixelRatio,高 DPI 设备上图形糊成一片 -
canvas.width赋值会清空当前画布(重置缓冲区),这是预期行为,不是 bug;但若没意识到这点,可能误以为“画的内容丢了”
混合设置 width/height 和 style 时的等比缩放陷阱
当 HTML 属性和 CSS 同时存在且比例不一致时,浏览器会强制等比缩放:比如 width="100" height="150" + style="width: 300px; height: 300px",宽度被放大 3 倍,高度就按同样倍率(3×150=450px)撑开,最终渲染尺寸是 300×450,画布被拉变形。
典型后果:
- 圆变成椭圆
-
ctx.arc(x, y, r, ...)画出来的不是正圆 - 鼠标坐标映射错乱,
getBoundingClientRect()和clientX/clientY换算后点不中路径
解决方案:要么只用 HTML 属性控制尺寸(适合固定尺寸场景),要么只用 JS 动态计算并赋值 canvas.width/canvas.height,再配 ctx.scale() 补偿缩放,CSS 仅用于布局定位。
响应式 canvas 必须结合 devicePixelRatio 动态重设
在 Retina 或高 DPI 屏幕上,window.devicePixelRatio === 2 时,若只设 style="width: 400px; height: 300px",而没调 canvas.width = 400 * devicePixelRatio,那实际缓冲区只有 200×150 像素,却要填满 400×300 物理像素区域,必然模糊。
实操建议:
- 用
ResizeObserver监听容器尺寸变化(比window.resize更精准) - 每次 resize 后,先读取容器
getBoundingClientRect(),再乘以devicePixelRatio得到目标缓冲区尺寸 - 赋值
canvas.width/canvas.height后,立刻调用ctx.scale(devicePixelRatio, devicePixelRatio),让绘图坐标系与视觉尺寸对齐 - 注意:
ctx.scale()会影响所有后续绘图操作,包括文字、阴影、变换,需统一设计坐标逻辑
最易被忽略的一点:devicePixelRatio 可能在页面生命周期中动态变化(比如用户缩放浏览器),不能只在初始化时读一次。



















