canvas.width和height必须设在HTML标签内或JS中,控制绘图缓冲区分辨率;仅用CSS设置会导致拉伸模糊、坐标偏移、图形变形,高DPI设备下更严重。

canvas.width 和 canvas.height 必须写在 HTML 标签里,不能靠 CSS 拉伸
直接用 style="width: 100%; height: 400px" 设置 <canvas> 尺寸,画布会模糊、圆变椭圆、鼠标点击坐标偏移——这不是渲染 bug,而是浏览器把一张固定像素的图强行拉伸显示。
根本原因:width 和 height 属性定义的是「绘图缓冲区分辨率」,即实际有多少个像素点可画;而 CSS 的 width/height 只控制「显示框大小」,两者不一致就触发位图缩放。
-
<canvas width="400" height="300"></canvas>→ 实际是 400×300 像素的位图 -
<canvas style="width:800px;height:600px"></canvas>→ 还是默认 300×150 像素,被拉伸 2.67 倍,必然失真 - 高 DPI 设备(如 MacBook、iPhone)下更明显:
window.devicePixelRatio> 1,原生尺寸不够 → 锯齿、文字发虚
JS 动态设置 canvas.width/height 会清空画布,不是“缩放”
canvas.width = 800 或 canvas.height = 600 是合法操作,但它的效果是重建整个缓冲区:所有已绘制内容消失,上下文状态(fillStyle、font、transform 等)全部重置。
这不是 CSS 那种视觉缩放,而是底层像素网格被销毁再初始化。所以每次改尺寸后,必须手动重绘。
立即学习“前端免费学习笔记(深入)”;
- ✅ 安全用法:
canvas.width = w; canvas.height = h;+ 紧接着调用重绘函数 - ❌ 危险混淆:
canvas.style.width = "800px"→ 不改像素,只拉伸显示,隐患静默存在 - ⚠️ 注意:
canvas.width = "800px"或canvas.width = 800.5会被忽略,回退到默认 300×150
响应式 canvas 初始化:三步缺一不可
单纯监听 resize 事件不够。要让画布既清晰又不失控,必须同步处理布局尺寸、设备像素比和显示样式。
典型流程:
- 读取当前显示尺寸:
const w = canvas.clientWidth;、const h = canvas.clientHeight; - 按设备像素比设置缓冲区:
canvas.width = w * window.devicePixelRatio;、canvas.height = h * window.devicePixelRatio; - 再缩放显示层:
canvas.style.width = w + "px";、canvas.style.height = h + "px";
务必在 DOMContentLoaded 后执行,或把脚本放在 </body> 前;否则 document.getElementById 找不到元素。
getContext('2d') 返回 null 的常见原因
canvas.getContext('2d') 返回 null 不代表代码写错,多数是环境问题,容易漏查。
- Canvas 元素还没插入 DOM(比如脚本在
<head>里执行,<canvas>还没解析) - 浏览器不支持(IE8 及更早版本),或用户禁用了 JavaScript
- Canvas 尺寸为 0(
width/height被设为 0 或未设导致回退默认值,但父容器不可见) - 某些旧版 Safari 在
display: none的容器里返回 null,需先 show 再 get
建议始终检查返回值:if (!ctx) throw new Error('Canvas 2D context not available');
真正容易被忽略的是:哪怕你 JS 初始化对了,如果后续某处 CSS 覆盖了 canvas 的显示尺寸(比如全局 img { max-width: 100% } 波及到 canvas),而没同步更新其 width/height 属性,失真就静默存在——直到你画一条 45° 线、放一张 PNG 或做精确点击检测时才突然崩掉。



















