Canvas 与 SVG

浏览器 2D 图形双引擎——Canvas 像素级绘制与性能优化、SVG 矢量图形与 DOM 交互、Canvas vs SVG 选型策略、OffscreenCanvas 多线程渲染。

Canvas 与 SVG

这个 topic 真正要回答的不是“哪个更好”

Canvas 和 SVG 很容易被讲成一道二选一题。

例如:

  • 性能用 Canvas
  • 交互用 SVG

这种总结有一点帮助。

但它不够。

更成熟的理解应该是:

Canvas 和 SVG 代表了浏览器里两种完全不同的图形思维。

Canvas 更像一块像素画布,你负责把结果画上去。

SVG 更像一组图形元素,你把图形对象声明出来,让浏览器去管理它们。

这两种思维的差异,会影响:

  • 性能
  • 交互
  • 调试
  • 可访问性
  • 维护方式

所以这不是单纯的 API 对比。

它本质上是两套渲染模型的对比。

为什么前端工程师需要真正理解它们

只要你开始做:

  • 可视化
  • 交互图形
  • 编辑器
  • 游戏和动画
  • 复杂图表

Canvas 和 SVG 的选择就会直接影响工程结果。

这类选择如果只靠经验口诀,常常会在项目变复杂后失效。

所以真正要学的,不是“记结论”。

而是理解两者各自的世界观。

一个更准确的定义

Canvas

Canvas 更适合被理解成:

浏览器中的即时模式绘图表面。

你每次绘制,都是在直接修改最终像素结果。

浏览器并不会自动帮你保留“这个圆”“那个矩形”作为对象语义。

SVG

SVG 更适合被理解成:

浏览器中的声明式矢量图形文档。

你定义的是对象:

  • 线
  • 文本
  • 路径

这些对象仍然存在于 DOM 世界里。

“即时模式”和“保留模式”为什么特别值得记

这是理解 Canvas 和 SVG 的关键一句话。

Canvas 更像即时模式。

意思是:

你告诉浏览器现在画什么,画完结果留下,但对象语义不自动保留。

SVG 更像保留模式。

意思是:

你声明对象,浏览器保留对象结构,之后还能继续样式、事件和语义化处理。

只要抓住这点,很多差异就很自然了。

Canvas 为什么经常更适合高密度绘制

Canvas 的优势,不是“它更高级”。

而是它把很多对象管理成本从浏览器那里拿掉了。

对于:

  • 很多粒子
  • 大量点
  • 高频重绘

这种场景,少一层 DOM 对象管理,通常会明显更合适。

所以 Canvas 常常在:

  • 游戏
  • 高频动画
  • 大量数据点可视化

这些场景里更自然。

但 Canvas 为什么又更容易变得难维护

正因为它更接近“把像素画上去”,所以很多事情也得你自己管。

例如:

  • 命中检测
  • 图元状态
  • 分层管理
  • 撤销重绘
  • 无障碍 fallback

这意味着,Canvas 虽然在渲染层可能更高效,但在工程层不一定更省事。

如果团队没有为“对象管理自行负责”做好准备,就会很快把 Canvas 代码写成难维护的大画布脚本。

SVG 为什么对前端工程师天然更亲切

因为它仍然在 DOM 语境里。

你天然会得到:

  • 元素结构
  • CSS 样式
  • 事件绑定
  • DevTools 可见性
  • 更好的无障碍基础

这让 SVG 很适合:

  • 图标
  • 可交互图表
  • 流程图
  • 少量矢量元素组成的界面

所以 SVG 的强项不是“所有图都能缩放”这么简单。

它的真正价值是:

图形对象仍然保留在前端开发者熟悉的声明式结构里。

为什么“SVG 交互更容易”不只是因为事件

很多人会说 SVG 好做交互,是因为它能直接绑 click 事件。

这当然对。

但更深层的原因是:

SVG 图形对象仍然有独立身份。

这意味着:

  • 样式好改
  • 状态好挂
  • 焦点可管理
  • 语义可增强

这对图表和编辑器类场景非常重要。

因为真正难的不是画出图形。

而是让图形可被操作、可被理解、可被调试。

为什么很多可视化项目最后会走向“SVG + Canvas 混合”

这是一个很常见的成熟结果。

因为两者各有强项。

例如:

  • 大量背景点和密集层用 Canvas
  • 交互层、坐标轴、标签用 SVG

这种分层思路很值得前端工程师记住。

它说明现实工程里最好的答案,常常不是单选题。

而是把不同渲染模型用在最适合的层上。

OffscreenCanvas 为什么重要

OffscreenCanvas 的意义,不在于“又多一个优化 API”。

它真正重要的地方是:

Canvas 终于能更自然地和 Worker 协同,减轻主线程压力。

这对于:

  • 高频渲染
  • 图像处理
  • 编辑器预览
  • 复杂动画

都很有意义。

因为只要图形工作过重,前端真正受伤的往往不是 FPS 本身。

而是主线程交互跟着一起变卡。

为什么 hit testing 是 Canvas 工程里的分水岭

很多人做 Canvas,前半段都挺顺利。

直到产品提了这些需求:

  • 点某个点要高亮
  • 拖某个图元要跟手
  • 鼠标移上去要有 tooltip

这时 hit testing 的复杂度就会开始爆发。

因为 Canvas 没有天然保留对象语义。

你要自己知道:

  • 当前点到的是谁
  • 这个区域对应哪个对象
  • 怎样维护空间索引

所以 Canvas 在交互复杂时,并不自动更轻松。

为什么 SVG 在节点很多时会掉得很难看

SVG 之所以舒服,是因为对象还在。

但这也是它的代价。

节点一多,浏览器就要维护:

  • DOM
  • 样式
  • 布局和绘制
  • 事件命中

所以 SVG 很容易在“元素数量暴涨”时出现明显性能问题。

这也是为什么很多经验结论会说:

少量高交互对象用 SVG,大量密集对象更偏向 Canvas。

无障碍为什么会把 Canvas 和 SVG 再次拉开

SVG 天生更容易进入无障碍体系。

因为它有元素语义基础,比较容易补标签、title、desc 和焦点行为。

Canvas 则更像一张图片表面。

如果业务真的要让图形本身可达、可读、可聚焦,Canvas 往往需要额外设计辅助结构。

这使得:

在强调可访问性和语义化的项目里,SVG 会天然更占优。

中国互联网语境里为什么 Canvas 常常和大屏、图形编辑、复杂可视化绑在一起

中国互联网里,Canvas 很多时候会在这些场景出现:

  • 大屏可视化
  • 海量点位图
  • 拖拽编辑器
  • 低代码设计器
  • 营销互动页和游戏化动画

这些场景共同特点是:

  • 元素多
  • 渲染频繁
  • 交互强

所以 Canvas 在中国语境里常常不只是“图形 API”,而是复杂视觉产品的基础设施之一。

海外语境里为什么 SVG 常常更容易和设计工具、图表系统一起出现

海外语境里,设计系统、文档站、分析型图表和交互式可视化产品很多。

这些产品往往更重视:

  • 语义结构
  • 可维护性
  • 可访问性
  • 和 DOM/CSS 生态的连续性

这会让 SVG 在很多“中等复杂度但交互丰富”的图形场景里非常顺手。

容易被讲浅的误区

误区一:Canvas 快,所以都该用 Canvas

不对。

快的是某类渲染模式,不代表整体工程更省。

误区二:SVG 适合简单图形,复杂一点就不行

也不对。

很多复杂交互图形系统依然非常适合 SVG,只是节点规模要受控。

误区三:只看初始渲染,不看交互和维护

这是最常见的选型失真。

误区四:二者只能二选一

很多成熟系统其实会混用。

面试或技术分享里怎么讲更成熟

一个更成熟的表达可以是:

Canvas 和 SVG 的差异,核心不在 API 多少,而在渲染模型。Canvas 更像即时模式绘图表面,适合高密度、高频重绘场景,但对象管理和交互命中往往要自己承担;SVG 更像保留模式的矢量文档,天然更适合声明式结构、DOM 交互和无障碍,但在节点规模很大时性能会下降。

真正成熟的选型不是记口诀,而是看对象数量、交互复杂度、可访问性要求和后续维护方式。

实践建议

实践一:同一个小图表分别用 Canvas 和 SVG 实现

不要只比“能不能画出来”。

要比:

  • 交互写法
  • 调试体验
  • 代码结构

实践二:做一个带 hover 命中的 Canvas 例子

这会让你非常快地理解 Canvas 的真实复杂度。

实践三:做一个 SVG 节点数量逐步增加的实验

观察何时开始卡顿,你会对“SVG 为什么不是无限扩展”有更直观的理解。

延展阅读