一、两种方式的本质区别
✅ 1. 直接设置 width / height 属性(HTML 属性)
<canvas width="800" height="600"></canvas>
👉 作用:
定义 Canvas 的“绘图缓冲区大小”(真实像素尺寸)
- 决定画布内部坐标系(0 ~ 800, 0 ~ 600)
- 决定绘制的清晰度
- 会重置画布内容
✅ 2. 用 CSS 控制大小
<canvas style="width: 800px; height: 600px;"></canvas>
👉 作用:
只改变显示尺寸(视觉缩放)
- 不改变内部像素
- 相当于把画布“拉伸/压缩”
- 会导致模糊
二、核心差异对比(重点)
| 维度 | HTML 属性 width/height | CSS width/height |
|---|---|---|
| 控制对象 | 画布内部像素 | 显示尺寸 |
| 是否影响清晰度 | ✅ 是 | ❌ 否(会拉伸) |
| 坐标系 | 改变 | 不变 |
| 是否会重置内容 | ✅ 会 | ❌ 不会 |
| 默认值 | 300 × 150 | 由布局决定 |
三、为什么 CSS 会导致模糊?
假设:
<canvas width="300" height="150" style="width:600px;height:300px;"></canvas>
👉 实际发生的是:
- 内部像素:300 × 150
- 显示尺寸:600 × 300
👉 浏览器做了:
把 300×150 的位图放大 2 倍
结果:
- 像素被插值 → 模糊
四、正确姿势(高清 Canvas)
👉 标准做法:
const canvas = document.querySelector('canvas')
const dpr = window.devicePixelRatio
canvas.width = 800 * dpr
canvas.height = 600 * dpr
canvas.style.width = '800px'
canvas.style.height = '600px'
const ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr)
💡 原理
- 内部用高分辨率(适配 Retina 屏)
- 外部用正常尺寸
- 绘制时缩放回来
五、为什么设置 width 会清空画布?
canvas.width = 800
👉 本质:
浏览器会重新创建一个新的绘图缓冲区
所以:
- 所有内容清空
- 状态(transform、style)也会重置
六、一个形象理解
你可以这样记:
🖼️ Canvas = 画布 + 显示框
width/height→ 画布分辨率(像素密度)CSS→ 画框大小(缩放)
👉 类比:
- HTML 属性 = 图片分辨率(比如 4K)
- CSS = 图片展示大小(比如缩小到 800px)
七、常见坑(面试高频)
⚠️ 1. 只用 CSS → 模糊
<canvas style="width: 800px"></canvas>
👉 ❌ 错
⚠️ 2. 忘记 devicePixelRatio
👉 在 Retina 屏会糊
⚠️ 3. 动态改 width 导致内容丢失
canvas.width = canvas.width // ❌ 也会清空
八、一句话总结
HTML 的 width/height 决定“画布像素”,CSS 决定“显示大小”,两者不一致就会导致拉伸和模糊