pin_drop当前位置:知识文库 ❯ 图文

多媒体:SVG简介 - 完整教程与代码示例

一、教程简介

SVG(Scalable Vector Graphics,可缩放矢量图形)是 W3C 制定的基于 XML 的矢量图形标准。与 Canvas 的位图渲染不同,SVG 使用 XML 描述图形,每个图形元素都是 DOM 节点,可以通过 CSS 和 JavaScript 进行操作。本教程将带你了解 SVG 的基本概念、<svg> 标签的使用、SVG 与 Canvas 的核心区别,以及 SVG 的适用场景。


二、核心概念

什么是 SVG

SVG 是一种使用 XML 描述二维矢量图形的标记语言,具有以下特点:

  • 矢量图形:基于数学公式描述,无限缩放不失真

  • DOM 元素:每个图形都是 DOM 节点,可单独操作

  • 文本可读:SVG 代码是纯文本,可编辑、可搜索

  • 样式可控:支持 CSS 样式和 JavaScript 交互

  • 动画支持:内置 SMIL 动画,也支持 CSS 动画

SVG 坐标系

SVG 使用与 Canvas 类似的坐标系:

  • 原点 (0, 0) 在左上角

  • X 轴向右为正方向

  • Y 轴向下为正方向

  • 单位可以是 px、em、%、pt 等

SVG 与 Canvas 的核心区别

特性 SVG Canvas
渲染模式 保留模式(Retained) 即时模式(Immediate)
图形表示 DOM 节点 像素位图
缩放 无限缩放不失真 缩放会模糊
事件处理 每个元素可绑定事件 需手动计算碰撞
DOM 操作 直接操作 DOM 无法操作单个图形
性能 元素多时性能下降 大量图形性能好
文本 可搜索、可选择 不可搜索
动画 SMIL + CSS + JS 仅 JavaScript
适用场景 图标、图表、地图 游戏、图像处理

三、语法与用法

svg 标签

代码示例

<svg width="400" height="300" xmlns="http://www.w3.org/2000/svg">
  <!-- SVG 内容 -->
</svg>

常用属性:

属性 说明 默认值
width 画布宽度 300
height 画布高度 150
viewBox 视图框(定义坐标系)
xmlns SVG 命名空间 必须指定
preserveAspectRatio 宽高比保持方式 xMidYMid meet

viewBox 属性

viewBox 定义 SVG 的内部坐标系,格式为 min-x min-y width height

代码示例

<!-- viewBox 定义内部坐标系为 0 0 100 100 -->
<!-- 实际显示尺寸为 400x400 -->
<svg width="400" height="400" viewBox="0 0 100 100">
  <!-- 圆心在 (50,50),半径 40,在 viewBox 坐标系中 -->
  <circle cx="50" cy="50" r="40" fill="#58a6ff" />
</svg>

内联 SVG 与外部引用

代码示例

<!-- 方式1:内联 SVG(推荐) -->
<svg width="200" height="200">
  <circle cx="100" cy="100" r="50" fill="red" />
</svg>

<!-- 方式2:img 标签引用 -->
<img src="image.svg" alt="SVG 图像" />

<!-- 方式3:CSS 背景引用 -->
<div style="background: url('image.svg');"></div>

<!-- 方式4:object 标签引用 -->
<object data="image.svg" type="image/svg+xml"></object>

四、代码示例

示例1:SVG 基本概念演示

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SVG 基本概念演示</title>
  <style>
    body {
      margin: 0;
      padding: 20px;
      background: #0d1117;
      color: #c9d1d9;
      font-family: 'Segoe UI', sans-serif;
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    h1 { margin-bottom: 10px; }
    .demo-grid {
      display: flex;
      gap: 20px;
      flex-wrap: wrap;
      justify-content: center;
    }
    .card {
      background: #161b22;
      border: 1px solid #30363d;
      border-radius: 8px;
      padding: 15px;
      text-align: center;
    }
    .card h3 {
      margin: 0 0 10px 0;
      font-size: 14px;
      color: #58a6ff;
    }
    svg {
      background: #0d1117;
      border-radius: 4px;
    }
    /* SVG CSS 样式 */
    .styled-rect {
      fill: #3fb950;
      stroke: #238636;
      stroke-width: 2;
      transition: fill 0.3s;
    }
    .styled-rect:hover {
      fill: #58a6ff;
    }
    .styled-text {
      font-family: 'Segoe UI', sans-serif;
      font-size: 14px;
      fill: #c9d1d9;
    }
  </style>
</head>
<body>
  <h1>SVG 基本概念演示</h1>

  <div class="demo-grid">
    <!-- 基本形状 -->
    <div class="card">
      <h3>基本形状</h3>
      <svg width="200" height="150" viewBox="0 0 200 150">
        <rect x="10" y="10" width="60" height="40" fill="#e94560" rx="5" />
        <circle cx="130" cy="30" r="25" fill="#58a6ff" />
        <ellipse cx="50" cy="110" rx="40" ry="25" fill="#3fb950" />
        <line x1="120" y1="80" x2="190" y2="140" stroke="#f8b500" stroke-width="3" />
        <polygon points="150,80 190,120 110,120" fill="#d2a8ff" />
      </svg>
    </div>

    <!-- viewBox 缩放 -->
    <div class="card">
      <h3>viewBox 缩放</h3>
      <svg width="200" height="150" viewBox="0 0 100 75" style="border:1px dashed #30363d;">
        <rect x="5" y="5" width="40" height="25" fill="#e94560" rx="3" />
        <circle cx="70" cy="20" r="15" fill="#58a6ff" />
        <text x="50" y="65" text-anchor="middle" class="styled-text" font-size="8">
          viewBox="0 0 100 75"
        </text>
      </svg>
    </div>

    <!-- CSS 样式 -->
    <div class="card">
      <h3>CSS 样式交互</h3>
      <svg width="200" height="150" viewBox="0 0 200 150">
        <rect class="styled-rect" x="20" y="20" width="70" height="50" rx="8" />
        <rect class="styled-rect" x="110" y="20" width="70" height="50" rx="8" />
        <rect class="styled-rect" x="65" y="85" width="70" height="50" rx="8" />
        <text x="100" y="145" text-anchor="middle" font-size="11" fill="#8b949e">
          鼠标悬停变色
        </text>
      </svg>
    </div>

    <!-- 渐变与滤镜 -->
    <div class="card">
      <h3>渐变与滤镜</h3>
      <svg width="200" height="150" viewBox="0 0 200 150">
        <defs>
          <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" style="stop-color:#e94560" />
            <stop offset="100%" style="stop-color:#58a6ff" />
          </linearGradient>
          <filter id="shadow1">
            <feDropShadow dx="2" dy="2" stdDeviation="3" flood-color="#000" flood-opacity="0.5" />
          </filter>
        </defs>
        <rect x="20" y="15" width="160" height="50" rx="10" fill="url(#grad1)" filter="url(#shadow1)" />
        <text x="100" y="45" text-anchor="middle" fill="#fff" font-size="16" font-weight="bold">
          渐变 + 阴影
        </text>
        <circle cx="60" cy="110" r="30" fill="url(#grad1)" filter="url(#shadow1)" />
        <circle cx="140" cy="110" r="30" fill="url(#grad1)" opacity="0.6" />
      </svg>
    </div>
  </div>

  <div style="margin-top:20px; max-width:800px;">
    <h2 style="font-size:16px; color:#58a6ff;">SVG vs Canvas 对比</h2>
    <svg width="800" height="200" viewBox="0 0 800 200">
      <!-- 表头 -->
      <rect x="0" y="0" width="800" height="30" fill="#21262d" />
      <text x="100" y="20" text-anchor="middle" fill="#c9d1d9" font-size="12" font-weight="bold">特性</text>
      <text x="300" y="20" text-anchor="middle" fill="#58a6ff" font-size="12" font-weight="bold">SVG</text>
      <text x="550" y="20" text-anchor="middle" fill="#3fb950" font-size="12" font-weight="bold">Canvas</text>

      <!-- 数据行 -->
      <g font-size="11" fill="#8b949e">
        <text x="100" y="52" text-anchor="middle">渲染模式</text>
        <text x="300" y="52" text-anchor="middle">保留模式 (DOM)</text>
        <text x="550" y="52" text-anchor="middle">即时模式 (像素)</text>

        <text x="100" y="77" text-anchor="middle">缩放</text>
        <text x="300" y="77" text-anchor="middle" fill="#3fb950">无损缩放</text>
        <text x="550" y="77" text-anchor="middle" fill="#e94560">缩放模糊</text>

        <text x="100" y="102" text-anchor="middle">事件处理</text>
        <text x="300" y="102" text-anchor="middle" fill="#3fb950">元素级事件</text>
        <text x="550" y="102" text-anchor="middle" fill="#e94560">手动碰撞检测</text>

        <text x="100" y="127" text-anchor="middle">大量元素</text>
        <text x="300" y="127" text-anchor="middle" fill="#e94560">性能下降</text>
        <text x="550" y="127" text-anchor="middle" fill="#3fb950">性能稳定</text>

        <text x="100" y="152" text-anchor="middle">文本搜索</text>
        <text x="300" y="152" text-anchor="middle" fill="#3fb950">可搜索</text>
        <text x="550" y="152" text-anchor="middle" fill="#e94560">不可搜索</text>

        <text x="100" y="177" text-anchor="middle">适用场景</text>
        <text x="300" y="177" text-anchor="middle">图标/图表/地图</text>
        <text x="550" y="177" text-anchor="middle">游戏/图像处理</text>
      </g>

      <!-- 分隔线 -->
      <line x1="200" y1="30" x2="200" y2="200" stroke="#30363d" />
      <line x1="400" y1="30" x2="400" y2="200" stroke="#30363d" />
      <line x1="0" y1="30" x2="800" y2="30" stroke="#30363d" />
    </svg>
  </div>
</body>
</html>

示例2:viewBox 与响应式 SVG

代码示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>viewBox 与响应式 SVG</title>
  <style>
    body {
      margin: 0;
      padding: 20px;
      background: #1a1a2e;
      color: #eee;
      font-family: 'Segoe UI', sans-serif;
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    .container {
      display: flex;
      gap: 20px;
      flex-wrap: wrap;
      justify-content: center;
    }
    .box {
      background: #16213e;
      border: 1px solid #333;
      border-radius: 8px;
      padding: 15px;
      text-align: center;
    }
    .box h3 { color: #58a6ff; font-size: 14px; margin: 0 0 10px; }
    .responsive-svg {
      width: 100%;
      max-width: 300px;
      height: auto;
    }
  </style>
</head>
<body>
  <h1>viewBox 与响应式 SVG</h1>
  <div class="container">
    <div class="box" style="width:220px;">
      <h3>固定尺寸 200x150</h3>
      <svg width="200" height="150" xmlns="http://www.w3.org/2000/svg">
        <rect width="200" height="150" fill="#0f172a" />
        <circle cx="100" cy="75" r="50" fill="#e94560" />
        <text x="100" y="80" text-anchor="middle" fill="#fff" font-size="14">固定</text>
      </svg>
    </div>

    <div class="box" style="width:220px;">
      <h3>viewBox 缩放</h3>
      <svg width="200" height="150" viewBox="0 0 100 75" xmlns="http://www.w3.org/2000/svg">
        <rect width="100" height="75" fill="#0f172a" />
        <circle cx="50" cy="37.5" r="25" fill="#58a6ff" />
        <text x="50" y="42" text-anchor="middle" fill="#fff" font-size="7">viewBox</text>
      </svg>
    </div>

    <div class="box" style="width:220px;">
      <h3>响应式 SVG</h3>
      <svg class="responsive-svg" viewBox="0 0 100 75" xmlns="http://www.w3.org/2000/svg">
        <rect width="100" height="75" fill="#0f172a" />
        <circle cx="50" cy="37.5" r="25" fill="#3fb950" />
        <text x="50" y="42" text-anchor="middle" fill="#fff" font-size="7">响应式</text>
      </svg>
    </div>
  </div>
</body>
</html>

五、浏览器兼容性

特性 Chrome Firefox Safari Edge IE
SVG 基本支持 4+ 3+ 3.2+ 12+ 9+
内联 SVG 4+ 3+ 3.2+ 12+ 9+
SVG CSS 动画 4+ 4+ 6+ 12+ 不支持
SVG SMIL 动画 4+ 4+ 6+ 不支持 不支持
SVG 滤镜 4+ 3+ 6+ 12+ 10+(部分)

六、注意事项与最佳实践

1. 始终指定 xmlns

代码示例

<!-- 独立 SVG 文件需要 xmlns -->
<svg xmlns="http://www.w3.org/2000/svg">
  <!-- 内容 -->
</svg>

<!-- 内联 SVG 在 HTML5 中可省略 xmlns -->
<svg>
  <!-- 内容 -->
</svg>

2. 使用 viewBox 实现响应式

代码示例

<!-- 推荐:使用 viewBox + width:100% -->
<svg viewBox="0 0 100 100" style="width:100%;height:auto;">
  <circle cx="50" cy="50" r="40" fill="red" />
</svg>

3. SVG 性能优化

  • 减少不必要的嵌套 <g> 元素

  • 避免过多的滤镜效果

  • 使用 <use> 复用元素

  • 对于复杂图形,考虑使用 Canvas

4. 可访问性

代码示例

<svg role="img" aria-label="一个红色的圆形">
  <title>红色圆形</title>
  <desc>这是一个填充为红色的圆形图形</desc>
  <circle cx="50" cy="50" r="40" fill="red" />
</svg>

5. SVG 作为 CSS 背景

代码示例

.icon {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2L2 7l10 5 10-5-10-5z' fill='%2358a6ff'/%3E%3C/svg%3E");
  width: 24px;
  height: 24px;
}

七、代码规范示例

代码示例

<!-- 推荐:SVG 文件标准结构 -->
<svg xmlns="http://www.w3.org/2000/svg"
     width="200" height="200"
     viewBox="0 0 200 200"
     role="img"
     aria-label="描述文字">
  <title>图形标题</title>
  <desc>图形详细描述</desc>

  <defs>
    <!-- 渐变、滤镜、图案等定义 -->
    <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
      <stop offset="0%" stop-color="#e94560" />
      <stop offset="100%" stop-color="#58a6ff" />
    </linearGradient>
  </defs>

  <!-- 图形内容 -->
  <g id="main-group">
    <rect x="10" y="10" width="180" height="180" rx="10" fill="url(#grad1)" />
  </g>
</svg>

八、常见问题与解决方案

常见问题

SVG 在 IE 中不显示?

确保使用 xmlns,避免使用 IE 不支持的特性(如 SMIL 动画),使用 polyfill 库。

SVG 缩放后文字变形?

使用 vector-effect="non-scaling-stroke" 防止描边缩放,或调整 viewBox

如何让 SVG 自适应容器大小?

使用 viewBox 配合 preserveAspectRatio 属性,并设置 CSS 宽度为 100%。

SVG 内联与外部引用的选择?

需要 CSS/JS 交互时使用内联,仅展示时使用外部引用。内联 SVG 可以直接使用 CSS 样式和 JavaScript 操作,但会增加 HTML 文件大小。


九、总结

SVG 是 Web 矢量图形的标准,关键要点:

  • 矢量图形:基于 XML 描述,无限缩放不失真

  • DOM 元素:每个图形都是 DOM 节点,可独立操作和添加事件

  • viewBox:定义内部坐标系,实现响应式缩放

  • CSS 样式:SVG 元素支持 CSS 样式和过渡动画

  • 保留模式:与 Canvas 的即时模式形成对比

  • 适用场景:图标、图表、地图、信息图等

下一教程将介绍 SVG 基本形状的绘制。

标签: SVG入门 矢量图形 svg标签 viewBox Canvas对比 响应式SVG

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: 多媒体:保存与恢复 - 完整教程与代码示例 下一篇: 多媒体:SVG基本形状 - 完整教程与代码示例

poll相关推荐