getContext('2d')失败主因是DOM未就绪、canvas尺寸为0、重复获取不同上下文、小程序缺type="2d",或高DPI下未适配devicePixelRatio。

Canvas 标签本身不绘图,必须通过 getContext() 获取上下文才能启用 2D 或 3D 能力;直接写 <canvas> 不会自动渲染任何内容。
为什么 getContext('2d') 失败或返回 null?
常见原因不是代码写错,而是 Canvas 元素未正确加载或上下文被重复获取:
- DOM 尚未就绪就调用
document.getElementById()—— 应放在DOMContentLoaded事件或<script>放在</body>前 - 同一 Canvas 被多次调用
getContext('2d')后又调getContext('webgl')—— 浏览器禁止混用,第二次会返回null - Canvas 的
width/height属性缺失或为 0 —— 即使 CSS 设置了尺寸,getContext仍可能失败或绘图区域为空 - 在微信小程序中漏写
type="2d"属性 —— 小程序的<canvas>必须显式声明type才能获取对应上下文
getContext('webgl') 和 getContext('webgl2') 的实际区别
不是“升级版替代”,而是两个独立接口,兼容性与能力差异明显:
-
getContext('webgl'):基于 OpenGL ES 2.0,所有现代浏览器都支持,但不支持整数纹理、uniform buffer object(UBO)、多重采样等高级特性 -
getContext('webgl2'):基于 OpenGL ES 3.0,Chrome/Firefox/Edge 80+ 支持,Safari 15.4+ 开始有限支持;若调用失败,应降级回'webgl',不能假设它一定可用 - 二者不可共存于同一 Canvas —— 第一次成功获取后,后续对另一类型的调用必返回
null - 检测是否支持 WebGL2 的安全写法是:
const gl = canvas.getContext('webgl2') || canvas.getContext('webgl');,但要注意着色器语法和 API 差异
2D 绘图中容易被忽略的像素对齐陷阱
Canvas 是像素级操作,但坐标系默认落在像素“线”上,不加处理会导致 1px 模糊或发虚:
- 绘制 1px 线条时,如果
ctx.lineWidth = 1且起始点是整数(如moveTo(10, 10)),线条会横跨两列像素,变灰变粗 - 修复方法:对坐标做
+ 0.5偏移,例如ctx.moveTo(10.5, 10.5),让线条精确落在单列像素中心 - 该问题在高 DPI 设备(如 Retina 屏)更明显,此时还需结合
window.devicePixelRatio缩放 canvas.width/height,并用ctx.scale(dpr, dpr)校准 - 使用
ctx.imageSmoothingEnabled = false可禁用图片缩放模糊,适用于像素画或 UI 图标
真正难的不是调用 getContext,而是理解它返回的对象是一次性绑定的“状态机”——一旦选了 2D 就不能再要 WebGL,且所有样式、变换、裁剪都持续生效直到显式重置。多数图形异常,根源不在画法,而在上下文状态残留。


















