何时使用 SVG 与何时使用 Canvas

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

SVG 和 canvas 都是可以在网页浏览器中绘制内容的技术,因此值得比较和理解何时哪种技术更适合。即使对它们有一个简单的了解,也能使在两者之间做出选择变得非常清晰。

  • 一个小巧的纯色图标?这显然是 SVG 的领域。
  • 一个交互式的控制台风格游戏?这显然是 canvas 的领域。

我知道我们还没有讲到 *为什么*,但我希望随着我们深入探讨,这一点会变得清晰。

SVG 是矢量图且声明式的

如果您知道需要矢量图形,那么 SVG 是您的选择。矢量图形在视觉上清晰锐利,并且往往比 JPG 等光栅图形的文件尺寸更小。

这使得 徽标成为 SVG 的一个非常常见的用例。SVG 代码可以直接放在 HTML 中,并且就像声明式的绘图指令一样。

<svg viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="50" />
</svg>

如果您非常关注图形的 *灵活性* 和 *响应性*,那么 SVG 是您的选择。

Canvas 是一个 JavaScript 绘图 API

您可以在 HTML 中放置一个 <canvas> 元素,然后在 JavaScript 中进行绘制。换句话说,您发出命令来告诉它 *如何* 绘制(这比 *声明式* 更 *命令式*)。

<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');
  var centerX = canvas.width / 2;
  var centerY = canvas.height / 2;
  var radius = 70;

  context.beginPath();
  context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
  context.fillStyle = 'green';
  context.fill();
</script>

SVG 位于 DOM 中

如果您熟悉 DOM 事件,例如 clickmouseDown 等,那么这些事件在 SVG 中也可用。从这方面来说,一个 <circle> 与一个 <div> 并没有太大的区别。

<svg viewBox="0 0 100 100">
  
  <circle cx="50" cy="50" r="50" />
  
  <script>
    document.querySelector('circle').addEventListener('click', e => {
      e.target.style.fill = "red";
    });
  </script>
  
</svg>

SVG 的可访问性

您可以为 canvas 提供文本替代方案。

<canvas aria-label="Hello ARIA World" role="img"></canvas>

您也可以在 SVG 中这样做,但是由于 SVG 及其内部结构可以直接位于 DOM 中,因此我们通常认为 SVG 是在您尝试构建可访问体验时使用的技术。换句话说,您可以构建一个辅助技术可以访问的 SVG,并找到具有其自身音频解释等的链接和子元素。

文本也牢牢地属于 SVG 的领域。SVG 实际上有一个 <text> 元素,它是可访问的 并且视觉上清晰——与 canvas 不同,在 canvas 中 文本通常是模糊的

Canvas 用于像素

正如您将在 Sarah Dranser 以下的比较中看到的,canvas 是一种表达 *像素,起舞吧!* 的方式。这是一种有趣的方式来解释这个概念,它比任何枯燥的技术说法都能更好地说明问题。

具有大量复杂细节和渐变的高度交互式作品是 canvas 的领域。出于这个原因,您会看到更多使用 canvas 而不是 SVG 构建的游戏,尽管总是存在 例外情况(请注意此游戏的简单矢量风格)。

CSS 可以与 SVG 互动

我们上面看到 SVG 可以位于 DOM 中,并且 JavaScript 可以进入 DOM 并执行操作。CSS 的情况与此类似。

<svg viewBox="0 0 100 100">
  
  <circle cx="50" cy="50" r="50" />
  
  <style>
    circle { fill: blue; }
  </style>
  
</svg>

请注意,对于这些示例,我已将 <script><style> 块放在 <svg> 内,这是有效的。但是,假设您已将 SVG 直接放在 HTML 中,您可以将其移出,或者让其他外部 CSS 和 JavaScript 执行相同操作。

我们有一个关于 SVG 属性和 CSS 的大量指南。但需要了解的是,CSS 擅长的事情在 SVG 中仍然是可能的,例如 :hover 状态和动画!

查看 Chris Coyier 的 CodePen 作品
ExxbpBE
(@chriscoyier)
CodePen 上。

组合

从技术上讲,它们并非完全互斥。一个 <svg> 可以绘制到一个 <canvas> 上。

正如 Blake Bowen 所证明的那样,您甚至可以使 canvas 上的 SVG 保持非常清晰!

查看 Blake Bowen 的 CodePen 作品
SVG 与 Canvas 缩放
(@osublake)
CodePen 上。

Ruth John 的比较

查看 Rumyra 的 CodePen 作品
SVG 与 Canvas
(@Rumyra)
CodePen 上。

Sarah Drasner 的比较

摘自 这条推文

DOM/虚拟 DOM Canvas
优点
非常适合 UI/UX 动画 像素,起舞吧!
非常适合分辨率无关的 SVG 非常适合制作令人印象深刻的 3D 或沉浸式内容
更容易调试 大量对象的移动
缺点
处理大量对象时性能下降 难以实现可访问性
因为您必须注意动画的方式 默认情况下不是分辨率无关的
崩溃成无

Shirley Wu 的比较

摘自 这条推文

SVG Canvas
优点 易于上手 性能非常好
更容易注册用户交互 易于更新
易于制作动画
缺点 潜在的复杂 DOM 入门工作量更大
大量元素时性能不佳 处理交互的工作量更大
必须编写自定义动画

许多人认为,包含大量对象(如 Shirley 所说的 1000 个以上)的情况属于 canvas 的领域。

SVG 是默认选择;canvas 是备选方案

这是一个强烈的观点,但我觉得它是对的。

总结

所以,如果我们重新审视前两个要点……

  • 一个简单的纯色图标? SVG 会放入 DOM 中,因此像按钮内部的图标这样的东西对于 SVG 来说非常有意义——更不用说它可以用 CSS 控制,并且拥有常规的 JavaScript 事件处理程序等
  • 一个交互式的控制台式游戏? 它将拥有很多很多移动元素、复杂的动画和交互、性能考虑。这些都是 canvas 擅长的方面。

然而,这里存在大量的中间地带。作为一名日常的网页设计师/开发人员,我发现 SVG 在实践层面上更有用。我不确定我是否曾经使用 canvas 做过任何生产工作。部分原因是我对 canvas 的了解不够深入。 我写了一本关于 SVG 的书,所以我在这方面做了更多的研究,但我知道 SVG 正在满足我的需求。