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 事件,例如 click
和 mouseDown
等,那么这些事件在 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 时使用 canvas”(其中“无法”可能意味着动画化数千个对象、单独操作每个像素等)。换句话说,SVG 应该是您的默认选择,canvas 是您的备用方案。
—— Benjamin De Cock (@bdc) 2019 年 10 月 2 日
总结
所以,如果我们重新审视前两个要点……
- 一个简单的纯色图标? SVG 会放入 DOM 中,因此像按钮内部的图标这样的东西对于 SVG 来说非常有意义——更不用说它可以用 CSS 控制,并且拥有常规的 JavaScript 事件处理程序等
- 一个交互式的控制台式游戏? 它将拥有很多很多移动元素、复杂的动画和交互、性能考虑。这些都是 canvas 擅长的方面。
然而,这里存在大量的中间地带。作为一名日常的网页设计师/开发人员,我发现 SVG 在实践层面上更有用。我不确定我是否曾经使用 canvas 做过任何生产工作。部分原因是我对 canvas 的了解不够深入。 我写了一本关于 SVG 的书,所以我在这方面做了更多的研究,但我知道 SVG 正在满足我的需求。