SVG 与 Canvas 对比

全面对比SVG和Canvas的特点、优缺点和适用场景。帮助开发者选择合适的前端图形技术方案。 前端绑图主要有两种技术:SVG 和 Canvas。它们各有特点,选对了事半功倍,选错了可能要重构。

核心区别

一句话概括:SVG 是声明式的,Canvas 是命令式的。

特性SVGCanvas
渲染方式矢量(保留模式)位图(立即模式)
图形操作DOM 元素像素操作
事件处理原生支持手动计算
缩放效果无损有损(模糊)
性能节点多时差节点多时好
文件格式文本 XML二进制/图片

渲染模式对比

SVG:保留模式

SVG 创建的每个图形都是 DOM 元素,浏览器会记住它们。你可以随时修改属性、添加事件。

点击图形改变颜色(SVG 原生事件)

<svg>
  <rect id="myRect" fill="#3498db" onclick="changeColor()"/>
</svg>
<script>
  document.getElementById('myRect').setAttribute('fill', 'red');
</script>

Canvas:立即模式

Canvas 是一块画布,画上去就变成像素了。想修改?重画一遍。

Canvas 画完后无法直接操作单个图形

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

ctx.fillStyle = '#3498db';
ctx.fillRect(10, 10, 80, 80);

ctx.fillStyle = '#2ecc71';
ctx.beginPath();
ctx.arc(150, 50, 40, 0, Math.PI * 2);
ctx.fill();

// 想修改?只能重画
ctx.clearRect(0, 0, 200, 100);
ctx.fillStyle = 'red';
ctx.fillRect(10, 10, 80, 80);

性能对比

SVG 性能特点

  • DOM 开销:每个图形都是 DOM 节点,多了会卡
  • 重绘优化:浏览器会自动优化重绘区域
  • 内存占用:简单图形内存小,复杂图形内存大

100 个元素:流畅

500 个元素:开始卡顿

Canvas 性能特点

  • 像素操作:直接操作像素,速度快
  • 手动管理:需要自己管理重绘逻辑
  • 内存稳定:不管画多少东西,内存占用稳定

功能对比

事件处理

SVG:每个图形都能绑定事件,像普通 DOM 元素一样。

<svg>
  <rect onclick="handleClick()" onmouseover="handleHover()"/>
</svg>

Canvas:没有原生事件支持,需要自己计算点击位置。

canvas.addEventListener('click', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;
  // 手动判断点击了哪个图形
  if (x > 10 && x < 90 && y > 10 && y < 90) {
    handleClick();
  }
});

动画

SVG:三种方式可选

  • SMIL 动画(声明式)
  • CSS 动画
  • JavaScript 操作 DOM

Canvas:只能用 JavaScript,需要手动实现动画循环。

function animate() {
  ctx.clearRect(0, 0, width, height);
  // 重绘所有内容
  requestAnimationFrame(animate);
}
animate();

文本处理

SVG:文本是可选中的,支持搜索。

Canvas:文本画上去就是像素,无法选中。

滤镜效果

SVG:内置丰富的滤镜,如模糊、投影、颜色矩阵等。

Canvas:部分滤镜支持,复杂效果需要手动实现。

选择建议

用 SVG 的场景

  • 图标、Logo
  • 简单图表
  • 需要事件交互的图形
  • 需要缩放的图形
  • 打印输出
  • 无障碍要求高的项目

用 Canvas 的场景

  • 游戏
  • 大量粒子效果
  • 实时数据可视化
  • 图像处理
  • 视频处理
  • 性能要求极高的场景

混合使用

很多项目会同时用到两者。比如:

  • 页面图标用 SVG
  • 数据大屏用 Canvas
  • 简单动画用 SVG,复杂动画用 Canvas

代码对比示例

画一个带描边的圆形:

SVG 方式

<svg width="100" height="100">
  <circle cx="50" cy="50" r="40" 
          fill="#3498db" 
          stroke="#2c3e50" 
          stroke-width="3"/>
</svg>

Canvas 方式

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

ctx.beginPath();
ctx.arc(50, 50, 40, 0, Math.PI * 2);
ctx.fillStyle = '#3498db';
ctx.fill();
ctx.strokeStyle = '#2c3e50';
ctx.lineWidth = 3;
ctx.stroke();

SVG 更简洁直观,Canvas 更灵活可控。