必须用 width 和 height 属性设置像素值,不能只靠 css;否则绘图模糊、坐标错乱、ispointinpath() 失效且不报错。css 的 width/height 仅控制显示框大小,不改变内部位图缓冲区,导致插值缩放、dpr 适配失败、鼠标事件坐标失准等问题。

必须用 width 和 height 属性设置像素值,不能只靠 CSS;否则绘图模糊、坐标错乱、isPointInPath() 失效,而且不报错,极难排查。
为什么不能只用 CSS 设置 canvas 尺寸
CSS 的 width 和 height 只控制显示框大小,不改变内部位图缓冲区。浏览器会对原始像素做插值缩放——比如默认 300×150 的画布被 CSS 拉到 600×400,线条变虚、圆变椭、导出 PNG 尺寸也不对。
-
ctx.lineWidth = 1实际渲染可能像 2px 宽(因缩放) - 鼠标事件换算坐标时,
getBoundingClientRect()返回的是 CSS 像素,和画布内部坐标系不匹配 - 高 DPR 设备(如 MacBook 或 iPhone)上问题更明显:物理像素不足 + 插值 = 锯齿+毛边
- 禁用所有 CSS 后对比渲染效果,是快速验证是否为缩放导致模糊的最直接办法
HTML 中直接写死 width 和 height 属性
这是最稳妥的初始化方式,尤其适合固定尺寸图表或游戏场景。
- 写法:
<canvas id="myCanvas" width="800" height="600"></canvas> - 此时画布缓冲区就是 800×600 像素,所有坐标、线宽、文字渲染都以此为准
- 后续 JS 中调用
getContext('2d')必须在 DOM 加载完成后,否则某些旧浏览器可能返回null - 如果之后用 JS 修改
canvas.width,会清空整个画布(这是预期行为,不是 bug)
响应式 canvas:动态适配视口并兼顾高清屏
要让 canvas 在不同设备上都清晰,关键是让缓冲区像素数 ≈ 显示区域 × window.devicePixelRatio。
- 先读取显示尺寸:
const w = canvas.clientWidth; const h = canvas.clientHeight; - 再设缓冲区:
canvas.width = w * window.devicePixelRatio; canvas.height = h * window.devicePixelRatio; - 最后用 CSS 回缩显示层:
canvas.style.width = w + "px"; canvas.style.height = h + "px"; - 必须监听
resize事件,并在触发后重新赋值width/height,再调用重绘函数 - 注意:不要用
window.innerWidth直接算,它包含滚动条宽度,且未考虑父容器限制;clientWidth更准确
常见踩坑点
很多模糊、点击偏移、动画卡顿的问题,根源都在尺寸设置环节。
- 把
canvas.width当成样式属性去改——错!必须赋给元素属性,不是style.width - 在
DOMContentLoaded前就执行 JS 初始化——可能导致getElementById找不到元素 - 响应式场景下只更新
style.width,没同步改canvas.width——缓冲区仍为旧尺寸,越缩越糊 - 用
getBoundingClientRect().width反推缓冲区大小——它返回的是 CSS 像素,无法还原 DPR 缩放前的真实像素数
真正麻烦的不是“怎么设”,而是设完之后要不要重绘、什么时候重绘、坐标换算逻辑要不要跟着变——这些细节不处理,画得再漂亮也点不准、动不了、导不出。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











