Canvas适合实时绘图、游戏等动态场景,但不支持图形级事件绑定与无障碍访问,需手动实现碰撞检测和状态管理,高DPI适配须用devicePixelRatio缩放缓冲区。

Canvas 能做实时绘图、游戏、数据可视化和图像处理,但不能直接响应点击某个图形,也不支持 DOM 事件绑定、缩放重绘自动适配、或无障碍访问。
Canvas 适合做需要逐像素控制的动态场景
比如粒子动画、实时滤镜、手写签名、WebGL 前置渲染层。它本质是一块位图画布,getContext('2d') 返回的上下文提供命令式绘图 API,所有绘制都靠 beginPath() → moveTo() → lineTo() → stroke() 这类调用完成,不生成任何可选中、可检查的节点。
常见错误现象:给 canvas 元素加 onclick,以为能点中画上去的圆形——实际只能拿到画布坐标,需手动做「点在圆内」数学判断。
- 适合场景:图表动画(如 ECharts 底层)、白板协作、视频帧处理(
drawImage()+getImageData()) - 不适合场景:带交互的流程图(建议 SVG)、需要 SEO 的图表、要键盘导航的图表
- 性能注意:频繁
clearRect()+ 重绘比 DOM 批量更新更可控,但过度save()/restore()会拖慢
Canvas 绘图后无法直接获取图形引用
画完一个矩形,没有 rectElement.id = 'my-rect' 这种操作。所有图形只是像素点,后续修改必须清空重画。这意味着你得自己维护一份“图形状态”数据结构。
立即学习“前端免费学习笔记(深入)”;
const shapes = [
{ type: 'circle', x: 100, y: 100, r: 20, fill: 'red' },
{ type: 'rect', x: 50, y: 50, w: 80, h: 40, stroke: '#000' }
];
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
shapes.forEach(shape => {
if (shape.type === 'circle') {
ctx.beginPath();
ctx.arc(shape.x, shape.y, shape.r, 0, Math.PI * 2);
ctx.fillStyle = shape.fill;
ctx.fill();
}
});
}
容易踩的坑:canvas.width 和 canvas.style.width 混用导致模糊;未监听 window.devicePixelRatio 就直接用 CSS 设置画布尺寸;重绘时忘了 beginPath() 导致路径叠加。
Canvas 在高 DPI 屏幕上默认模糊怎么办
这是最常被忽略的兼容性问题:CSS 设置 width: 300px 的画布,其内部绘图缓冲区仍是 300×150 像素(浏览器默认),在 Retina 屏上被拉伸,线条发虚。
- 正确做法是用
devicePixelRatio手动放大缓冲区,再用 CSS 缩回视觉尺寸 - 必须在设置
canvas.width/canvas.height后,再调用ctx.scale(dpr, dpr) - 不要只改
style.width,否则绘图坐标系会错乱
function setupHiDPICanvas(canvas) {
const dpr = window.devicePixelRatio || 1;
const rect = canvas.getBoundingClientRect();
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
const ctx = canvas.getContext('2d');
ctx.scale(dpr, dpr);
}Canvas 不能替代 SVG 的地方很明确
如果需求里包含「点击某条折线高亮它」「右键菜单弹出编辑选项」「导出为矢量 PDF」「用屏幕阅读器读出柱状图数值」,Canvas 就不是第一选择。SVG 是真实 DOM 元素, 可以加 aria-label、tabindex、addEventListener('click'),Canvas 全得自己模拟。
复杂点在于:有些项目试图用 Canvas 模拟 SVG 行为(比如维护 shape 列表 + 自己实现 hit-testing),结果代码量翻倍、调试困难、缩放逻辑重复造轮子。真要兼顾性能和交互,不如用 SVG 做主体 + Canvas 做特效层,或直接选 OffscreenCanvas 配合 Web Worker 做预计算。











