canvas的物理尺寸只能由width和height属性控制,CSS样式无效;因二者分别定义像素缓冲区与显示框大小,不一致会导致缩放失真、坐标错位、高DPI模糊等问题。

canvas 的物理尺寸只能由 width 和 height 属性控制,CSS 样式不起作用 —— 这不是限制,而是设计如此。
为什么 canvas.style.width 不能改变物理尺寸
浏览器把 canvas.width 和 canvas.height 当作位图缓冲区的像素数,直接分配内存并建立坐标系;而 style.width 只是“把这个框拉多宽”,不碰底层像素。两者不一致时,浏览器只能插值缩放,结果就是模糊、变形、坐标错位。
常见错误现象:
- 用
canvas.style.width = "800px"后画圆变成椭圆 -
isPointInPath()判断失效,鼠标点不准 - 导出的 PNG 是 300×150 像素,哪怕 canvas 看起来很大
- 高 DPI 屏幕上文字发虚、线条毛边(
window.devicePixelRatio > 1时尤其明显)
设置 width/height 的三种合法方式
必须赋整数值(字符串或数字均可),单位隐含为像素,且不能带单位后缀或小数。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- HTML 属性:
<canvas width="640" height="480"></canvas>—— 最稳妥,页面加载即生效 - JS 赋值:
canvas.width = 640; canvas.height = 480;—— 会清空画布,适合响应式重设 - JS 字符串赋值:
canvas.width = "640"; canvas.height = "480";—— 效果同上,但"640px"或"640.5"会被忽略,回退到默认 300×150
响应式场景下必须同步处理三件事
仅靠 ResizeObserver 监听容器变化还不够,物理尺寸、CSS 显示尺寸、绘图缩放必须联动。
- 先读父容器的 clientWidth/clientHeight(逻辑尺寸)
- 乘以
window.devicePixelRatio得到目标物理像素数,赋给canvas.width/canvas.height - 用
ctx.scale(ratio, ratio)把绘图坐标系缩放回来,否则所有图形变小 - 再设
canvas.style.width和canvas.style.height回逻辑尺寸,保证 DOM 布局正常
漏掉任意一步,就可能触发滚动条、模糊、或内容被裁切。
容易被忽略的细节:默认值不是“未定义”
不写 width 和 height,画布照样有物理尺寸 —— 就是硬编码的 300 和 150。这不是浏览器猜测,是 HTML5 规范强制要求。
这意味着:
- 只写
width="400",height仍是 150,不是“自适应” - 动态设置
canvas.width = 0会清空画布,但再设回非零值才恢复缓冲区 - 服务端渲染或 SSR 场景中,若初始 HTML 没写这两个属性,客户端 JS 必须显式初始化,否则永远卡在 300×150
物理尺寸一旦定下来,就决定了所有坐标的映射精度、内存占用、以及后续是否能无损缩放 —— 它不是样式开关,而是画布的“基因”。


















