Skip to content

SVG 内联矢量图

SVG(Scalable Vector Graphics)是一种基于 XML 的矢量图形格式。内联 SVG 是将 SVG 代码直接嵌入到 HTML 文档中,这种方式可以让你用 CSS 样式化和用 JavaScript 操作 SVG 元素。本节将介绍内联 SVG 的基本用法。

前置知识

阅读本节前,建议先了解:canvas 绘图操作

基础概念

SVG 是一种矢量图形格式,它用 XML 标记语言描述图形,而不是像素数据。与位图(如 JPEG、PNG)不同,SVG 图形可以无损缩放到任意大小,始终保持清晰。

内联 SVG(Inline SVG)是将 <svg> 标签直接放在 HTML 文档中。这种方式的优势在于:SVG 元素成为 DOM 的一部分,可以用 CSS 样式化,可以用 JavaScript 交互。

语法

基本内联 SVG

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>内联 SVG</title>
</head>
<body>
  <h1>内联 SVG 基础</h1>

  <!-- 基本圆形 -->
  <svg width="100" height="100" viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="#4285f4"/>
  </svg>

  <!-- 基本矩形 -->
  <svg width="150" height="100" viewBox="0 0 150 100">
    <rect x="10" y="10" width="130" height="80" fill="#34a853" rx="8"/>
  </svg>

  <!-- 基本线条 -->
  <svg width="200" height="100" viewBox="0 0 200 100">
    <line x1="10" y1="50" x2="190" y2="50" stroke="#ea4335" stroke-width="3"/>
  </svg>

  <!-- 基本多边形 -->
  <svg width="120" height="120" viewBox="0 0 120 120">
    <polygon points="60,10 110,90 10,90" fill="#fbbc05"/>
  </svg>
</body>
</html>

详细说明

SVG viewBox 属性

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>viewBox</title>
</head>
<body>
  <h1>viewBox 属性</h1>

  <!--
    viewBox="minX minY width height"
    定义了 SVG 的坐标系统和可视区域
  -->

  <!-- SVG 逻辑尺寸 100x100,但渲染为 200x200 -->
  <svg width="200" height="200" viewBox="0 0 100 100">
    <circle cx="50" cy="50" r="40" fill="#4285f4"/>
  </svg>

  <!-- viewBox 还可以裁剪内容 -->
  <svg width="100" height="100" viewBox="25 25 50 50">
    <circle cx="50" cy="50" r="40" fill="#ea4335"/>
    <!-- 只显示圆的中心区域 -->
  </svg>
</body>
</html>

用 CSS 样式化 SVG

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>CSS 样式化 SVG</title>
  <style>
    /* SVG 的 class、id 都可以用 CSS 选择器 */
    .icon-blue {
      fill: #4285f4;
      transition: fill 0.3s;
    }
    .icon-blue:hover {
      fill: #1a73e8;
    }

    .icon-red {
      fill: #ea4335;
    }

    .icon-outline {
      fill: none;
      stroke: #333;
      stroke-width: 2;
    }

    /* SVG 的 stroke 和 fill 可以独立控制 */
    .stroked-circle {
      fill: rgba(66, 133, 244, 0.2);
      stroke: #4285f4;
      stroke-width: 2;
    }
  </style>
</head>
<body>
  <h1>CSS 样式化 SVG</h1>

  <!-- CSS 控制 fill -->
  <svg width="50" height="50" viewBox="0 0 50 50">
    <circle class="icon-blue" cx="25" cy="25" r="20"/>
  </svg>

  <svg width="50" height="50" viewBox="0 0 50 50">
    <circle class="icon-red" cx="25" cy="25" r="20"/>
  </svg>

  <!-- CSS 控制 stroke -->
  <svg width="50" height="50" viewBox="0 0 50 50">
    <circle class="icon-outline" cx="25" cy="25" r="20"/>
  </svg>

  <!-- CSS 控制渐变 -->
  <svg width="50" height="50" viewBox="0 0 50 50">
    <circle class="stroked-circle" cx="25" cy="25" r="20"/>
  </svg>
</body>
</html>

用 JavaScript 操作 SVG DOM

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>JavaScript SVG</title>
</head>
<body>
  <h1>JavaScript 操作 SVG</h1>

  <svg id="mySvg" width="200" height="200" viewBox="0 0 200 200">
    <circle id="myCircle" cx="100" cy="100" r="50" fill="#4285f4"/>
  </svg>

  <br>
  <button onclick="changeColor()">改变颜色</button>
  <button onclick="moveCircle()">移动圆</button>
  <button onclick="animateCircle()">动画</button>

  <script>
    // SVG 元素是 DOM 节点,可以用 JS 操作
    var circle = document.getElementById('myCircle');

    function changeColor() {
      circle.setAttribute('fill', '#ea4335');
    }

    function moveCircle() {
      var cx = Math.random() * 100 + 50;
      var cy = Math.random() * 100 + 50;
      circle.setAttribute('cx', cx);
      circle.setAttribute('cy', cy);
    }

    function animateCircle() {
      var radius = 50;
      var angle = 0;
      function step() {
        angle += 0.05;
        var cx = 100 + Math.cos(angle) * 30;
        var cy = 100 + Math.sin(angle) * 30;
        circle.setAttribute('cx', cx);
        circle.setAttribute('cy', cy);
        circle.setAttribute('r', radius + Math.sin(angle * 3) * 10);
        requestAnimationFrame(step);
      }
      step();
    }
  </script>
</body>
</html>

内联 SVG 的常用形状

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>SVG 形状</title>
</head>
<body>
  <h1>SVG 常用形状</h1>

  <!-- circle: 圆形 -->
  <svg width="60" height="60" viewBox="0 0 60 60">
    <circle cx="30" cy="30" r="25" fill="#4285f4"/>
  </svg>

  <!-- rect: 矩形 -->
  <svg width="60" height="40" viewBox="0 0 60 40">
    <rect x="5" y="5" width="50" height="30" fill="#34a853" rx="5"/>
  </svg>

  <!-- ellipse: 椭圆 -->
  <svg width="80" height="50" viewBox="0 0 80 50">
    <ellipse cx="40" cy="25" rx="35" ry="20" fill="#fbbc05"/>
  </svg>

  <!-- line: 直线 -->
  <svg width="100" height="20" viewBox="0 0 100 20">
    <line x1="5" y1="10" x2="95" y2="10" stroke="#ea4335" stroke-width="3"/>
  </svg>

  <!-- polyline: 折线 -->
  <svg width="100" height="50" viewBox="0 0 100 50">
    <polyline points="10,40 30,10 50,30 70,10 90,40"
              fill="none" stroke="#673ab7" stroke-width="2"/>
  </svg>

  <!-- polygon: 多边形 -->
  <svg width="50" height="50" viewBox="0 0 50 50">
    <polygon points="25,5 45,40 5,40" fill="#e91e63"/>
  </svg>

  <!-- path: 通用路径 -->
  <svg width="80" height="60" viewBox="0 0 80 60">
    <path d="M10 50 Q40 5 70 50" fill="none" stroke="#00bcd4" stroke-width="2"/>
  </svg>
</body>
</html>

实战示例

SVG 图标按钮

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>SVG 图标</title>
  <style>
    body { font-family: sans-serif; }
    .icon-btn {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      padding: 8px 16px;
      border: 1px solid #ddd;
      border-radius: 8px;
      background: #fff;
      cursor: pointer;
    }
    .icon-btn:hover {
      background: #f5f5f5;
    }
    .icon-btn svg {
      width: 20px;
      height: 20px;
    }
  </style>
</head>
<body>
  <h1>SVG 图标按钮</h1>

  <!-- 搜索图标 -->
  <button class="icon-btn">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <circle cx="11" cy="11" r="8"/>
      <line x1="21" y1="21" x2="16.65" y2="16.65"/>
    </svg>
    搜索
  </button>

  <!-- 首页图标 -->
  <button class="icon-btn">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <path d="M3 12l9-9 9 9"/>
      <path d="M9 21V12h6v9"/>
    </svg>
    首页
  </button>

  <!-- 设置图标 -->
  <button class="icon-btn">
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <circle cx="12" cy="12" r="3"/>
      <path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M16.36 16.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M16.36 7.64l1.42-1.42"/>
    </svg>
    设置
  </button>
</body>
</html>

注意事项

  • 内联 SVG 会增加 HTML 文件体积,但可以被 Gzip 压缩
  • SVG 元素是 DOM 的一部分,会触发浏览器重绘
  • 内联 SVG 可以被搜索引擎索引(但不包含文本内容时)
  • 复杂的 SVG(如地图)不适合内联
  • 内联 SVG 的 CSS 和 JS 作用域与页面共享

最佳实践

  • 简单图标和图形使用内联 SVG
  • 使用 viewBox 确保可缩放
  • 使用 currentColor 让 SVG 颜色跟随 CSS
  • 为 SVG 添加 aria-labelrole="img" 提升无障碍
  • 使用 <title><desc> 为 SVG 提供描述
  • 复杂图形使用外部 SVG 文件通过 <img> 引入

下一节

继续学习:SVG 与 canvas 对比

参考链接