Skip to content

位图和矢量图

  • 位图: 经常用到的图像格式,如 PNG/JPEG 等文件, 它的像素都是固定的, 放大后会失真
  • 矢量图: 与位图不同放大后不会失真, 它是根据数据动态计算的, 所以放大后不会失真

SVG 介绍

  • SVG 是一种基于 XML 的图形语言,它可以用于创建各种图形和图像。
  • SVG 文件是一个 XML 文档,它包含一个 <svg> 元素,该元素包含其他元素。
  • <svg> 元素可以包含其他元素,如 <rect><circle><line><path><polygon><polyline><text> 等。
  • SVG 文件可以用于创建各种图形和图像,包括矢量图形、线条图形、圆形图形、椭圆形图形、文本图形、图像图形等。

快速开始

注意

SVG 也可以通过标签的属性直接设置宽度和高度, 同时也能够使用 CSS 来设置宽度和高度 不同与 canvas 的是, 使用 SVG 设置宽度和高度并不会缩放和失真

html
<svg width="500" height="500">
  <!-- 画圆 -->
  <circle cx="50" cy="50" r="40" fill="blue" />

  <!-- 绘制文字 -->
  <text x="10" y="120">Hello World</text>
</svg>

使用 SVG 的四种常见方式

1.内嵌到 HTML 标签中

html
<svg width="500" height="500">
  <circle cx="50" cy="50" r="40" fill="blue" />
</svg>

2.通过浏览器打开 SVG 图片

可以将这个 xml 保存成一个单独的 demo.svg 文件, 然后用浏览器打开

html
<!-- 注意: 如果保存成单独的文件, 比如加上 xmlns 属性, 且值必须是这个地址 -->
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="40" fill="blue" />
</svg>

3.在 html 的 img 标签中应用

html
<img src="./demo.svg" />

4.作为 css 的背景来使用

css
#box {
  width: 500px;
  height: 500px;
  background-image: url("./demo.svg");
}

绘制矩形标签

html
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <!--
    rect: 绘制矩形标签, 参数与 canvas 类似
    x,y:  确定矩形开始绘制的位置
    width,height: 确定矩形的宽度和高度
    fill: 填充的颜色
    stroke: 修改描边的颜色
    stroke-width: 修改描边的宽度
    rx,ry: 设置圆角的半径
  -->
  <rect x="100" y="100" width="100" height="100" fill="#f00" stroke="#0f0" stroke-width="10" rx="10" ry="10"></rect>
</svg>

绘制椭圆/圆形标签

html
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <!-- 利用矩形+圆角可以画圆 -->
  <rect x="100" y="100" width="100" height="100" rx="50"></rect>

  <!-- 直接使用 circle 标签画圆
    cx,cy: 圆心的位置
    r: 圆的半径
  -->
  <circle cx="300" cy="300" r="50"></circle>
</svg>

<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <!-- 使用 rect + 圆角 绘制椭圆形 -->
  <rect x="100" y="100" width="200" height="100" rx="100" ry="50"></rect>

  <!-- ellipse 直接绘制椭圆
    cx,cy: 圆心的位置
    rx: 水平方向的半径
    ry: 垂直方向的半径
  -->
  <ellipse cx="300" cy="300" rx="100" ry="50"></ellipse>
</svg>

绘制直/折线和多边形

html
<!--- 绘制折线-->
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <!-- line 绘制直线:
    x1,y1: 直线起点的坐标
    x2,y2: 直线结束点的坐标
    stroke: 绘制的颜色
  -->
  <line x1="100" y1="100" x2="300" y2="100" stroke="#f00"></line>

  <!-- polyline 绘制折线
    points: 设置绘制线的所有点, 两两一对
    stroke: 设置绘制线的颜色
    fill: 默认填充黑色, none 表示不需要填充
  -->
  <polyline points="100 200 300 200 300 300" stroke="#f00" fill="none"></polyline>

  <!-- polyline 绘制多边形: 将最后一个点和坐标和第一个坐标相同即可, 但是这样做比较麻烦 -->
  <!--<polyline points="100 200 300 200 300 300 100 200" stroke="#f00" fill="none"></polyline>-->
</svg>

<!--- 绘制多边形-->
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <!-- polygon 绘制多边形: 他会自动关闭路径, 将最后一个点与第一个点链接起来
    points: 与 polyline 参数一样, 只是polygon会自动关闭路径, 而 polyline 不会
  -->
  <polygon points="100 200 300 200 300 300" stroke="#f00" fill="none"></polygon>
</svg>

SVG 常用属性

属性作用
fill修改填充颜色
fill-opacity修改填充颜色的透明度
stroke修改描边颜色
stroke-width修改描边的宽度
stroke-opacity修改描边颜色的透明度
stroke-linecap修改线段两端的样式 butt(默认)/square/round
stroke-dasharray设置虚线
stroke-dashoffset设置虚线偏移位置
stroke-linejoin设置折线转角样式 miter/bevel/round

注意这些属性都是可以在 css 中直接使用的

html
<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="referrer" content="no-referrer" />
    <title>Canvas and SVG</title>
    <style>
      svg {
        border: 1px solid #f00;
      }
      svg polygon {
        fill: none;
        stroke: #f00;
      }
    </style>
  </head>
  <body>
    <svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
      <polygon points="100 200 300 200 300 300"></polygon>
    </svg>
  </body>
</html>

path 路径

  • 字母指令与数字坐标中间可以不使用空格隔开
  • 路径的字母指令是区分大小写的
    • 大写: 绝对定位(以 svg 的左上角作为参考点)
    • 小写: 相对定位(以上一个点作为参考点)
  • 路径的字母指令表如下
指令说明
MmoveTo 起点坐标
LlineTo 其他点的坐标
Hhorizontal lineTo 和上一个点的 Y 坐标相同
Vvertical lintTo 和上一个点的 X 坐标相同
A绘制椭圆弧度 A(rx,ry,xr,laf,sf,x,y)
ZclosePath 闭合路径
html
<!DOCTYPE html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="referrer" content="no-referrer" />
    <title>Canvas and SVG</title>
    <style>
      svg {
        border: 1px solid #f00;
      }
    </style>
  </head>
  <body>
    <svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
      <!-- 这种情况和 canvas 类似, 无法很好的闭合路径, 会有"瑕疵" -->
      <!--<path d="M 100 100 L 300 100 L 300 300 L 100 100" stroke="#f00" stroke-width="10" fill="none"></path>-->

      <!-- 使用Z闭合路径, 但是这样写起来比较复杂, 可以用 HV 两个属性来简化下 -->
      <!--<path d="M 100 100 L 300 100 L 300 300 Z" stroke="#f00" stroke-width="10" fill="none"></path>-->

      <!-- SVG 路径: 可以绘制任意图形, 不过参数比较多一些
        d: 绘制路径的数据, 需要用字母指令来确定
      -->
      <path d="M100 100 H300 V300 Z" stroke="#f00" stroke-width="10" fill="none"></path>
    </svg>

    <svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
      <!-- M100 100 和 L300 100 都是相对与 svg 左上角的位置来定位的 -->
      <path d="M 100 100 L 300 100" stroke="#f00" stroke-width="10" fill="none"></path>
    </svg>

    <svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
      <!-- l300 100 是相对于 M100 100 的位置来定位的 -->
      <path d="M 100 100 l 300 100" stroke="#f00" stroke-width="10" fill="none"></path>
    </svg>
  </body>
</html>

绘制文本

html
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <line x1="0" y1="250" x2="500" y2="250" stroke="#f00"></line>
  <line x1="250" y1="0" x2="250" y2="500" stroke="#f00"></line>
  <!-- text 绘制文字, 与 canvas 一样, x,y是设置文字的左下角
    x,y: 确定文字绘制的位置(左下角)
    style: 设置文字的样式
    fill: 设置文字填充颜色(默认是填充而不是描边)
    stroke: 设置文字描边的颜色
    text-anchor: 文字水平方向的对齐方式(取值有: start/end/middle)
    dominant-baseline: 文字垂直方向的对齐方式(取值有: text-after-edge/middle)
    dx: 指定一个字符与上一个字符的间隙宽度
    dy: 指定一个字符在垂直方向的偏移量
  -->
  <text
    x="250"
    y="250"
    style="font-size: 30px"
    fill="f00"
    text-anchor="middle"
    dominant-baseline="middle"
    dx="10 20 30 40 50"
    dy="10 20 30 40 50"
  >
    Hello
  </text>
</svg>

<!-- 绘制多行文本 -->
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <text fill="#00f">
    <!-- 如果自己有 fill 属性会使用自己的fill 属性 -->
    <tspan x="100" y="100" fill="#f00">hello</tspan>
    <tspan x="100" y="200" fill="#0f0">world</tspan>
    <!-- 没有会继承 text 的 fill 属性 -->
    <tspan x="100" y="300">SVG</tspan>
  </text>
</svg>

绘制超链接

html
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg">
  <!-- a 标签的用法与 html 的 a 标签类似:
    只要将需要添加超链接的内容放到标签中间即可添加超链接
    xlink:href 指定需要跳转的url
    xlink:title 鼠标移动上去后显示的提示文本
    target 超链接在浏览器中打开的方式
      _self (默认值)当前标签页打开
      _blank 新标签页打开
  -->
  <a xlink:href="https://github.com" xlink:title="Github" target="_blank">
    <text x="100" y="100">open github.com</text>
  </a>
</svg>

绘制图片

html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <!--
    image 绘制图片 默认情况下, 原图是多大, 绘制出来就是多大
    xlink:href 设置图片的 url
    width: 设置图片的宽度
    height: 设置图片的高度
    当设置的尺寸和原图的实际尺寸不一样时: 高度填满, 宽度等比拉伸
    x,y: 设置图片绘制的位置
  -->
  <image
    width="400px"
    height="200px"
    x="100"
    y="100"
    xlink:href="https://raw.githubusercontent.com/liaohui5/images/refs/heads/main/images/20220420132604.png"
  ></image>
</svg>

结构标签

标签作用
gg 是 group 的缩写, 可以将多个元素组合成一组元素, 以便于统一操作: 比如旋转,缩放,添加样式等, 对 g 标签设置的所有样式都会应用这组元素中的所有子元素
useg 结构元素封装的原数组, 可以通过 use 来进行复制使用
defsdefs 包裹的元素/元素组默认不会显示出来, 只有用到后才会显示出来
symbol与 defs 类似, 包裹的元素默认不会显示

symbol 与 g 标签的区别, symbol 可以自定义 viewBoxpreserveAspectRatio 属性

html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <!-- 统一给组内的所有元素设置 fill 属性, 如果组内的子元素有 fill 就不设置 -->
  <g fill="red" id="rects">
    <rect x="10" y="10" width="100" height="100"></rect>
    <rect x="10" y="120" width="100" height="100"></rect>
    <rect x="10" y="230" width="100" height="100" fill="blue"></rect>
  </g>

  <!-- 使用已经编组的元素 -->
  <use xlink:href="#rects" x="150"></use>
</svg>

<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <!-- 使用 defs 后, 默认不会显示, 相当于只是定义了一个模板 -->
  <defs>
    <g id="rects1">
      <rect x="10" y="10" width="100" height="100"></rect>
      <rect x="10" y="120" width="100" height="100"></rect>
      <rect x="10" y="230" width="100" height="100" fill="blue"></rect>
    </g>
  </defs>

  <!-- 只有 use 到后, 才会显示 -->
  <use xlink:href="#rects1" x="10" fill="red"></use>
  <use xlink:href="#rects1" x="150" fill="red"></use>
</svg>

<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <!-- 使用 symbol 后, 默认不会显示, 相当于只是定义了一个模板 -->
  <symbol>
    <g id="rects2">
      <rect x="10" y="10" width="100" height="100"></rect>
      <rect x="10" y="120" width="100" height="100"></rect>
      <rect x="10" y="230" width="100" height="100" fill="blue"></rect>
    </g>
  </symbol>

  <!-- 只有 use 到后, 才会显示 -->
  <use xlink:href="#rects2" x="10" fill="red"></use>
  <use xlink:href="#rects2" x="150" fill="red"></use>
</svg>

裁剪 & 蒙版

  • clipPath: 裁剪, 只有这个路径范围内的内容才会显示, 路径外的内容不会显示
  • mask: 蒙版与裁剪类似
    • 裁剪路径是可见与不可见的 突变
    • 蒙版路径是可见与不可见的 渐变, 简单来说就是蒙版可以设置透明度

使用裁剪/蒙版: 需要通过这种格式 url(#clipPathId) 来指定

html
<!-- 默认: 圆形盖住矩形 -->
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <rect x="100" y="100" width="300" height="200" fill="blue"></rect>
  <circle cx="200" cy="200" r="100" fill="red"></circle>
</svg>

<!-- 裁剪: 矩形只显示被圆形盖住的部分 -->
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <clipPath id="myClipPath">
    <circle cx="200" cy="200" r="100" fill="red"></circle>
  </clipPath>

  <rect clip-path="url(#myClipPath)" x="100" y="100" width="300" height="200" fill="blue"></rect>
</svg>

<!-- 蒙版: 矩形只显示被圆形盖住的部分, 但是两者的颜色会混合变为紫色 -->
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <mask id="myMask">
    <!-- 设置蒙版的透明度可以用 rgba 的格式来设置 -->
    <circle cx="200" cy="200" r="100" fill="rgba(255, 0, 0, 0.5)"></circle>
  </mask>
  <rect mask="url(#myMask)" x="100" y="100" width="300" height="200" fill="blue"></rect>
</svg>

渐变色

和 canvas 中类似, 在 svg 中也可以设置渐变色

  • 线性渐变: linearGradient
  • 径向渐变: radialGradient
html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <!-- 默认不要显示渐变 -->
  <defs>
    <!--
      默认情况下: 与 canvas 渐变方案不同的是, x1 和 y1 的取值不是具体的坐标位置
      而是从左到右的百分比: 取值为 0~1(比如x: 最左边是0 最右边是 1)
        x1, y1: 线性渐变的起点
        x2, y2: 线性渐变的终点
        x1=0,y1=0: 表示左上角的位置
        x2=1,y2=1: 表示右下角的位置
      如果需要修改成类似 cnavas 那样的指定具体的坐标, 可以使用:
        gradientUnits="objectBoundingBox": 百分比(默认值)
        gradientUnits="userSpaceOnUse": 举例svg左上角具体坐标
      注意这个取值是区分大小写的, 不能写错
    -->
    <linearGradient id="myColor" x1="0" y1="0" x2="1" y2="1" gradientUnits="objectBoundingBox">
      <!-- stop 标签表示渐变的进度和颜色
        offset: 渐变的进度
        stop-color: 渐变的颜色
      -->
      <stop offset="0" stop-color="red"></stop>
      <stop offset="0.5" stop-color="green"></stop>
      <stop offset="1" stop-color="blue"></stop>
    </linearGradient>

    <linearGradient id="myColor2" x1="100" y1="350" x2="400" y2="550" gradientUnits="userSpaceOnUse">
      <stop offset="0" stop-color="red"></stop>
      <stop offset="0.5" stop-color="green"></stop>
      <stop offset="1" stop-color="blue"></stop>
    </linearGradient>
  </defs>

  <!-- 注意使用渐变颜色方案的格式为: url(#gradientId) -->
  <rect x="100" y="100" width="300" height="200" fill="url(#myColor)"></rect>
  <rect x="100" y="350" width="300" height="200" fill="url(#myColor2)"></rect>
</svg>

画笔

用自定义的图形来填充其他图形

html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <!--
      默认情况下: patternUnits="objectBoundingBox"
        width: 被填充图形的总宽度的 20%
        height: 被填充图形的总高度的 20%
      可以修改为: patternUnits="userSpaceOnUse"
        width: 20 个像素
        height: 20 个像素
    -->
    <pattern id="myPattern" width="0.2" height="0.2">
      <circle cx="10" cy="10" r="10" fill="red"></circle>
    </pattern>

    <pattern id="myPattern2" width="20" height="20" patternUnits="userSpaceOnUse">
      <circle cx="10" cy="10" r="10" fill="red"></circle>
    </pattern>
  </defs>

  <!-- 应用画笔来填充这个矩形 -->
  <rect x="100" y="100" width="300" height="200" fill="url(#myPattern)"></rect>
  <rect x="100" y="400" width="300" height="200" fill="url(#myPattern2)"></rect>
</svg>

形变

SVG 的形变和 canvas 的形变规则一样, 操作的是整个坐标系而不是具体的元素

html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
  <rect x="100" y="100" width="300" height="200" fill="red"></rect>
  <rect x="100" y="100" width="300" height="200" fill="blue" transform="translate(100, 100)"></rect>
</svg>

ViewBox

viewBox

viewBox 就是可视区域, 用户能用眼睛看到的区域 默认情况下, 可视区域和内容区域的大小是一样的 但是我们可以手动修改可视区域的大小

viewBox 属性格式: viewBox="x y width height"

  • x: 修改可视区域的 x 方向位置
  • y: 修改可视区域的 y 方向位置
  • width/height: 修改可视区域的尺寸, 近大远小
html
<!-- 默认情况 viewBox="0 0 200 200" -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>

<!-- viewBox="50 50 200 200": 表示: 将可视区域向右下各偏移 50 像素 -->
<svg viewBox="50 50 200 200" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>

<!-- viewBox="-50 -50 200 200": 表示: 将可视区域向左上各偏移 50 像素 -->
<svg viewBox="-50 -50 200 200" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>

<!-- viewBox="0 0 400 400": 表示将可视区域放大到400,里面的内容会随之缩放 -->
<svg viewBox="0 0 400 400" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>

<!-- viewBox="0 0 100 100": 表示将可视区域缩小到100,里面的内容会随之缩放 -->
<svg viewBox="0 0 100 100" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <rect x="50" y="50" width="100" height="100" fill="red"></rect>
</svg>

preserveAspectRatio

preserveAspectRatio 的取值有这些:

  • xMin: viewport 和 viewBox 左边对齐
  • xMid: viewport 和 viewBox x 轴的中心对齐
  • xMax: viewport 和 viewBox 右边对齐
  • YMin: viewport 和 viewBox 上边对齐
  • YMid: viewport 和 viewBox y 轴的中心对齐
  • YMax: viewport 和 viewBox 下边对齐

注意: 这些取值必须严格遵循大小写

html
<svg viewBox="0 0 200 200" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="50" fill="#f00" />
</svg>

<!-- 放大视口: 在原宽高基础上等比例放大 -->
<svg viewBox="0 0 400 400" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="50" fill="#f00" />
</svg>

<!-- 缩小视口: 在原宽高基础上等比例缩小 -->
<svg viewBox="0 0 150 150" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="50" fill="#f00" />
</svg>

<!-- 缩小视口: 但不是等比例缩小 -->
<svg viewBox="0 0 50 150" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="50" fill="#0f0" />
</svg>

<!-- 缩小视口: 但不是等比例缩小 -->
<svg viewBox="0 0 150 50" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="50" fill="#0f0" />
</svg>

<!--
  默认情况下: 如果viewBox 的尺寸是根据原宽高的尺寸等比例缩放, 那么调整后的viewBox区域的xy
  和内容区域的 x/y 对齐, 如果 viewBox 不是根据原宽高的尺寸等比例缩放的, 那么系统就会自动调
  整 viewBox 的位置, 我们设置的 x/y 就会失效, 此时就需要 viewBox x/y 和内容区域的 xy 保持重
  合, 那么就需要设置 preserveAspectRatio 属性, 来手动控制对齐方式
-->
<!-- 放大视口: 但不是等比例放大, 同时设置 preserveAspectRatio -->
<svg viewBox="0 0 50 150" preserveAspectRatio="xMinYMin" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="50" fill="#00f" />
</svg>

<!-- 缩小视口: 但不是等比例缩小, 同时设置 preserveAspectRatio -->
<svg viewBox="0 0 150 50" preserveAspectRatio="xMinYMin" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="50" cy="50" r="50" fill="#00f" />
</svg>

SVG 动画

在 svg 中, 总共有3种动画标记:

  • animate
  • animateTransform
  • animateMontion

在 svg 中, 总共有2种类使用动画的方式

  • 创建动画, 告诉动画标记哪个元素需要执行动画
  • 插件元素, 在元素中说明需要执行什么动画
  • 借助CSS, 利用CSS来选中SVG元素, 然后执行动画

svg 中的动画属性:

  • attributeType: 属性类型, 可以是 CSS 属性, 也可以是 SVG 属性
  • attributeName: 属性名称
  • from/to: 动画运行的过程, 从哪到哪
  • dur: 动画持续时间
  • fill: 动画结束之后的状态(freeze:保持执行动画后的状态, remove:(默认值)恢复执行动画前的状态)

基本使用

html
<!-- 先创建动画, 然后用 xlink:href 应用到元素上 -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle id="myCircle" cx="100" cy="100" r="50" fill="#f00" />
  <!-- 将 #myCircle 的 r 属性 从 50 慢慢的变成 100, 动画持续3s钟  -->
  <animate attributeName="r" from="50" to="100" dur="3s" xlink:href="#myCircle" />
</svg>

<!-- 先创建元素, 然后说明要如何执行动画 -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="#0f0">
    <animate attributeName="r" from="50" to="100" dur="3s" fill="freeze" />
  </circle>
</svg>

<!-- 直接使用 css 来让 SVG 执行动画 -->
<svg width="300" height="300" viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
  <style>
    @keyframes pulse {
      0% {
        transform: scale(1);
      }
      50% {
        transform: scale(0.5);
      }
      100% {
        transform: scale(1);
      }
    }
    .heart {
      animation: pulse 1s linear infinite;
      transform-origin: 50% 50%;
    }
  </style>
  <g class="heart">
    <path
      d="M150 270 Q75 225 45 150 Q30 105 75 75 Q120 45 150 90 Q180 45 225 75 Q270 105 255 150 Q225 225 150 270"
      fill="red"
    />
    <path
      d="M150 270 Q225 225 255 150 Q270 105 225 75 Q180 45 150 90 Q120 45 75 75 Q30 105 45 150 Q75 225 150 270"
      fill="red"
    />
  </g>
</svg>

动画的常用属性

  • repeatCount: 执行动画的次数(indefinite: 无限次执行)
  • repeatDur: 总共执行动画的时间
  • begin: 执行动画的触发事件+执行动画的延迟时间
  • restart: 动画开始之后,是否可以立即重新开始执行
    • always: 不管是否执行完, 立即重新开始执行
    • whenNotActive: 只有执行完之后才能重新开始执行
    • never: 动画执行完之后不重置, 就只执行一次
  • calcMode: 设置每个动画片段的动画表现
    • linear: (默认) 匀速动画
    • discrete: 非连续动画,瞬间完成
    • paced: 整个动画始终以相同的速度进行
    • spline: 自定义动画, 需配合 keySplines 属性来动画过度效果
  • keyTimes: 划分动画片段(类似CSS 的 keyfames)
  • values: 划分对应取值片段的值
html
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="#f00">
    <animate attributeName="r" from="50" to="100" dur="1s" repeatCount="indefinite" />
  </circle>
</svg>

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="#0f0">
    <animate attributeName="r" from="50" to="100" dur="1s" repeatDur="3s" />
  </circle>
</svg>

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="#00f">
    <animate attributeName="r" from="50" to="100" dur="1s" begin="2s" />
  </circle>
</svg>

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="gray">
    <animate attributeName="r" from="50" to="100" dur="1s" begin="click" />
  </circle>
</svg>

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="#ff0">
    <animate attributeName="r" from="50" to="100" dur="1s" begin="click+1s" />
  </circle>
</svg>

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="#f0f">
    <animate attributeName="r" from="50" to="100" dur="1s" restart="whenNotActive" />
  </circle>
</svg>

<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="skyblue">
    <animate attributeName="r" keyTimes="0;0.5;1" dur="1s" values="25;50;100" />
  </circle>
</svg>

复合动画

html
<!-- 1.动画执行过程中改变多个属性 -->
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="#f00">
    <!-- 如果要改变多个属性, 那么需要多个 animate 元素 -->
    <animate attributeName="r" from="50" to="100" dur="1s" repeatCount="indefinite" />
    <animate attributeName="fill" from="#f00" to="#0f0" dur="1s" repeatCount="indefinite" />
  </circle>
</svg>

<!-- 2.按照顺序执行动画 -->
<svg width="400" height="200" xmlns="http://www.w3.org/2000/svg">
  <circle cx="100" cy="100" r="50" fill="#f00">
    <animate id="toRight" attributeName="cx" from="100" to="300" dur="1s" />

    <!-- toRight.end 表示等待 id="toRight" 的动画结束时才执行 -->
    <animate attributeName="cx" from="300" to="100" dur="1s" begin="toRight.end" />
  </circle>
</svg>

<!-- 3.互相等待, 无限往返 -->
<circle cx="100" cy="100" r="50" fill="#f00">
  <!-- 0;toLeft.end 表示:
      第一次不等待执行执行, 必须这样, 否则一直互相等待, 根本无法开始执行动画
      后续等待 id="toRight" 的动画结束时才执行
  -->
  <animate id="toRight" attributeName="cx" from="100" to="300" dur="1s" begin="0;toLeft.end" />
  <animate id="toLeft" attributeName="cx" from="300" to="100" dur="1s" begin="toRight.end" />
</circle>

形变动画

类似CSS的形变动画, 如果更熟悉CSS的话, 也可以直接使用CSS

html
<svg width="400" height="400" xmlns="http://www.w3.org/2000/svg">
  <rect x="0" y="0" width="100" height="100">
    <!-- type: 形变的类型, 比如: translate, rotate, scale 等 -->
    <animateTransform attributeName="transform" type="translate" from="0 0" to="100 100" dur="1s" fill="freeze" />
  </rect>
</svg>

路径动画

所谓的路径动画, 就是沿着一个 path 执行动画

html
<svg width="600" height="600" xmlns="http://www.w3.org/2000/svg" viewBox="-100 -100 600 600">
  <!-- 这个Path仅仅作为参考,并不是必须的 -->
  <path d="M0 0 C0 300 300 300 300 0" stroke="#f00" stroke-widht="2" fill="none"></path>
  <rect x="0" y="0" width="40" height="40" fill="rgba(255,0,0,0.5)">
    <animateMotion path="M0 0 C0 300 300 300 300 0" dur="3s" fill="freeze" rotate="auto"></animateMotion>
  </rect>
</svg>

SVG 脚本编程

所谓的 SVG 脚本编程, 就是使用 JS 来操作 SVG 元素, 了解一下开源库

js
window.onload = () => {
  // 注: 如果要使用 JS 动态的创建 svg 元素, 必须指定 namespace, 否则不生效
  const SVG_NS = "http://www.w3.org/2000/svg";
  const svgDom = document.createElementNS(SVG_NS, "svg");
  svgDom.setAttribute("width", "600");
  svgDom.setAttribute("height", "600");

  const circleDom = document.createElementNS(SVG_NS, "circle");
  circleDom.setAttribute("cx", "50");
  circleDom.setAttribute("cy", "50");
  circleDom.setAttribute("r", "50");
  circleDom.setAttribute("fill", "#f00");
  svgDom.appendChild(circleDom);

  // 注: 如果要设置带有 xlink:xxx 这样的属性必须要指定 namespace, 否则不生效
  const imageDom = document.createElementNS(SVG_NS, "image");
  const XLinkNS = "http://www.w3.org/1999/xlink";
  imageDom.setAttributeNS(XLinkNS, "xlink:href", "https://avatars.githubusercontent.com/u/29266093");
  imageDom.setAttribute("x", "100");
  imageDom.setAttribute("y", "100");
  imageDom.setAttribute("width", "200");
  imageDom.setAttribute("height", "200");
  svgDom.appendChild(imageDom);

  document.body.appendChild(svgDom);
};
html
<!doctype html>
<html lang="zh-cn">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="referrer" content="no-referrer" />
    <title>Canvas and SVG</title>
    <style>
      svg {
        border: 1px solid #f00;
      }
    </style>
  </head>
  <body>
    <svg width="600" height="600" xmlns="http://www.w3.org/2000/svg">
      <circle cx="50" cy="50" r="50" fill="#f00" />
      <image xlink:href="https://avatars.githubusercontent.com/u/29266093" x="100" y="100" width="200" height="200" />
    </svg>
    <script src="./index.js" type="module"></script>
  </body>
</html>

Released under the MIT License.