Skip to main content

SVG

介绍

可缩放矢量图形(Scalable Vector Graphics,SVG),是一种用于描述基于二维的矢量图形的,基于 XML 的标记语言。

MDN 参考

优点:

  • 保真,不会失真,体积小
  • 灵活,可以用 CSS 和 JS 来操作

SVG 可以成为任何复杂的组合图形,支持渐变、旋转、滤镜效果、JavaScript 接口等功能。

  • SVG 使用的坐标系是以页面的左上角为(0,0)坐标点
  • 向右是 x 轴正方向,向下是 y 轴正方向
  • 以像素为坐标单位

svg 标签

<svg>表示根元素

<svg width="300" height="200">
<rect width="100%" height="100%" fill="red" />
<circle cx="150" cy="100" r="80" fill="green" />
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
</svg>

示例定义了一个 300*200px 的 SVG 画布,x="150" y="125"表示坐标位置(150,125),cx="150" cy="100"表示圆心位置(150,100)

<svg width="200" height="200" viewBox="0 0 100 100"></svg>

这里定义的画布尺寸是 200*200px。但是,viewBox 属性定义了画布上可以显示的区域:从(0,0)点开始,100 宽 x 100 高的区域。这个 100 x 100 的区域,会放到 200*200 的画布上显示,于是就形成了放大两倍的效果。可以将 viewBox 理解为截图

viewBox(min-x min-y width height)

path 标签

<path>元素是 SVG 基本形状中最强大的一个,没有之一。

<path>元素的形状是通过属性 d 定义的,属性 d 的值是一个“命令+参数”的序列。

每一个命令都用一个关键字母来表示,命令有两种表示方式:

  1. 用大写字母,表示采用绝对定位
  2. 用小写字母,表示采用相对定位(相对上一个点定位)
指令参数含义
Mx y将画笔移动到点(x,y),仅仅是移动画笔,但不画线
Lx y从当前的点绘制线段到点(x,y)
Hx从当前的点绘制水平线段到点(x,y0),y0 表示绘制前画笔所在 y 轴坐标,即 y 轴不变
Vy从当前的点绘制竖直线段到点(x0,y),x0 表示绘制前画笔所在 x 轴坐标,即 x 轴不变
Arx ry x-axis-rotation large-arc-flag sweep-flag x y从当前的点绘制一段圆弧到点(x,y)
Cx1 y1, x2 y2, x y从当前的点绘制一段三次贝塞尔曲线到点(x,y)
Sx2 y2, x y特殊版本的三次贝塞尔曲线(省略第一个控制点)
Qx1 y1, x y绘制二次贝塞尔曲线到点(x,y)
Tx y特殊版本的二次贝塞尔曲线(省略控制点)
Z无参数会从当前点画一条直线到路径的起点,绘制闭合图形

示例:

<svg width="200" height="200">
<path d="M10 10 H 90 V 90 H 10 L 10 10" />
<path d="M10 10 h 80 v 80 h -80 Z" />
<path d="M90 20 H 120 V 120 H 20 L 100 80 L 60 70" fill="#f00" />
</svg>

第一个路径是:画笔移动到起点(10,10),水平移动到 x=90 的位置,垂直移动到 y=90 的位置,水平移动到 x=10 的位置,最后回到起点。

第二个路径是:画笔移动到起点(10,10),右移 80px 画一条水平线,下移 80px 画一条垂直线,左移 80px,最后回到起点。

前两个路径都是画了一个矩形。填充色默认黑色。

基本图形

图形标签模板含义
矩形<rect><rect x="60" y="10" rx="10" ry="10" width="30" height="30"/>x:起点横坐标,y:起点纵坐标,rx:倒角 x 轴方向半径,ry:倒角 x 轴方向半径,width:宽度,height:高度
圆形<circle><circle cx="100" cy="100" r="50" fill="#fff"></circle>cx:圆心横坐标,cy:圆心纵坐标,r:半径
椭圆<ellipse><ellipse cx="75" cy="75" rx="20" ry="5"/>cx:椭圆心横坐标,cy:椭圆心纵坐标,rx:椭圆 x 轴方向半径,ry:椭圆 y 轴方向半径
直线<line><line x1="10" x2="50" y1="110" y2="150"/>x1,y1:起点,x2,y2:终点
折线<polyline><polyline points="60 110, 65 120, 70 115, 75 130, 80 125, 85 140, 90 135, 95 150, 100 145"/>每两个点以空格配对为一个坐标点,逗号隔开形成坐标集合。连成折线。
多边形<polygon><polygon points="50 160, 55 180, 70 180, 60 190, 65 205, 50 195, 35 205, 40 190, 30 180, 45 180"/>类似折线,最后一个点会自动闭合第一个点,形成闭环。

贝塞尔曲线

控制点描述的是曲线起始点的斜率,曲线上各个点的斜率,是从起点斜率到终点斜率的渐变过程。

三次贝塞尔曲线 C,控制点(x1,y1)和(x2,y2),终点(x,y)

语法:C x1 y1, x2 y2, x y

<path d="M10 10 C 20 20, 40 20, 50 10" />

通常情况下,一个点某一侧的控制点是它另一侧的控制点的对称(以保持斜率不变)。

S 命令可以用来创建与前面一样的贝塞尔曲线,但是,如果 S 命令跟在一个 C 或 S 命令后面,则它的第一个控制点会被假设成前一个命令曲线的第二个控制点的中心对称点。如果 S 命令单独使用,前面没有 C 或 S 命令,那当前点将作为第一个控制点。

<path d="M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" />

二次贝塞尔曲线 Q,只需要一个控制点,用来确定起点和终点的曲线斜率。

<path d="M10 80 Q 95 10 180 80" />

T 命令可以用来创建与前面一样的二次贝塞尔曲线,通过前一个控制点,推断出一个新的控制点。这意味着,在第一个控制点后面,可以只定义终点,就创建出一个相当复杂的曲线。需要注意的是,T 命令前面必须是一个 Q 命令,或者是另一个 T 命令,才能达到这种效果。如果 T 单独使用,那么控制点就会被认为和终点是同一个点,所以画出来的将是一条直线。

<path d="M10 80 Q 52.5 10, 95 80 T 180 80" />

symbol 标签

symbol 标签可以用来定义矢量图形,然后在其他地方引用。

<svg>
<symbol id="icon1" viewBox="0 0 40 40">
<circle fill="#000" opacity="0.2" cx="20" cy="20" r="20"></circle>
</symbol>
</svg>

只有使用了<use>标签,才能使用 symbol 标签定义的矢量图形。

<use xlink:href="#icon1"></use>

g 标签

g 标签定义一个可复用的模块

<g style="fill: #1994d0;">
<path id="icon1" class="cls-4" d="M20,33Z" style="stroke: inherit; filter: none; fill: inherit" />
</g>

<use xlink:href="#icon1" style="stroke: url(#linear-gradient); filter: none; fill: none" />

如果有多个 path 表示一个图形,结构是松散的,不便于控制的话,那么可以使用 g 标签来包裹住这些 path

动画

动画方案:CSS、JS、SMIL

css: animation、tansform、transition

  • stroke-dasharray,指定描边短线的长度和间隔。如果值的个数为奇数,则这个值的数列重复一次变成偶数个值
  • stroke-dashoffset,描边短线的起始位置距离图形绘制起点的偏移量。正负值可以决定顺/逆时针
stroke-dasharray: 5;
stroke-dasharray: 5, 3;
stroke-dasharray: 5, 3, 2; /* 等同于 5,3,2,5,3,2 */

stroke-dashoffset: 5;

SMIL

SMIL 表示标签化动画,如<animate /><animateMotion />等。使用 SMIL 的 SVG 动画

<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
<rect width="10" height="10">
<animate attributeName="rx" values="0;5;0" dur="10s" repeatCount="indefinite" />
</rect>
</svg>
  • attributeName 目标属性名称
  • from 起始值
  • to 结束值
  • dur 持续时间
  • repeatCount 重复次数,indefinite 表示无限次

路径动画

  • offset-path 指定元素运动的路径
  • offset-distance 指定元素沿路径运动的距离,可以是数值或者百分比单位
  • offset-position 定义元素的初始位置
  • offset-anchor 指定路径框内的原点
  • offset-rotate 定义元素沿路径的角度,默认是 auto,表示自动计算当前路径的切线方向,并朝着这个方向前进

使元素沿着不规则路径运动,需要设置元素的 offset-path 和原路径重合

方式一、通过 css 的 offset-path 实现

<span class="horse"></span>
<svg width="280" height="150" viewBox="0 0 280 150">
<path id="road" d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>
.horse {
position: absolute;
offset-path: path('M10,80 q100,120 120,20 q140,-50 160,0');
/* offset-path: url('#road'); */
animation: move 3s linear infinite;
}
@keyframes move {
100% {
offset-distance: 100%;
opacity: 0;
}
}

方式二、使用 SVG SMIL animateMotion 元素实现

<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#cd0000">

<animateMotion
path="M10,80 q100,120 120,20 q140,-50 160,0"
begin="0s"
dur="3s"
rotate="auto"
repeatCount="indefinite"
/>
<animate attributeName="opacity" from="1" to="0" begin="0s" dur="3s" repeatCount="indefinite" />
</text>
<path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
</svg>

文字描边动画

可以在 figma 上创建文字,单击右键选择Outline stroke设置描边,设置描边的宽度,颜色等,去掉填充色。右键复制为 svg

通过 svg 提供的getTotalLength()获取每个 path 的长度,用该长度设置 stroke-dashoffset的值

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
height: 100vh;
background-color: #000;
display: flex;
align-items: center;
justify-content: center;
}

.logo {
animation: fill-ani 500ms ease forwards 2000ms;
}
.logo path:nth-child(1) {
stroke-dasharray: 239;
stroke-dashoffset: 239;
animation: line-ani 2s ease forwards;
}
.logo path:nth-child(2) {
stroke-dasharray: 213;
stroke-dashoffset: 213;
animation: line-ani 2s ease forwards 300ms;
}
.logo path:nth-child(3) {
stroke-dasharray: 263;
stroke-dashoffset: 263;
animation: line-ani 2s ease forwards 600ms;
}
.logo path:nth-child(4) {
stroke-dasharray: 510;
stroke-dashoffset: 510;
animation: line-ani 3s ease forwards 900ms;
}
.logo path:nth-child(5) {
stroke-dasharray: 595;
stroke-dashoffset: 595;
animation: line-ani 5s ease forwards 1200ms;
}

@keyframes line-ani {
to {
stroke-dashoffset: 0;
fill: #ffffff;
}
}
@keyframes fill-ani {
from {
fill: transparent;
}
to {
fill: #fff;
}
}
</style>
</head>
<body>
<svg class="logo" width="262" height="63" viewBox="0 0 262 63" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M31.3413 21.9573L31.3205 22.4773H31.8409H41.2727H41.7031L41.7672 22.0517C42.2039 19.1505 41.865 16.5711 40.7174 14.3395C39.5723 12.113 37.7541 10.3899 35.2917 9.16635C32.8258 7.92588 29.8278 7.31818 26.3182 7.31818C22.8653 7.31818 19.6712 7.91956 16.7417 9.12846C13.8289 10.3216 11.4003 12.008 9.46662 14.1912L9.46646 14.1914C7.54015 16.3683 6.32575 18.9162 5.82542 21.8243L5.82538 21.8243L5.82435 21.8308C5.26115 25.3821 5.96638 28.2871 8.02346 30.4576C10.0329 32.5778 12.9698 34.1058 16.7841 35.075C16.7847 35.0752 16.7854 35.0754 16.786 35.0755L21.6461 36.3473L21.6461 36.3474L21.6547 36.3495C23.2545 36.7382 24.5762 37.183 25.6274 37.6794L25.6274 37.6795L25.6349 37.6829C26.6901 38.1599 27.4087 38.7173 27.8408 39.3328C28.2486 39.9136 28.3991 40.6507 28.2347 41.5961L28.2346 41.5961L28.2337 41.6018C28.0688 42.6191 27.6169 43.5208 26.8643 44.3152C26.1078 45.1137 25.109 45.7495 23.8501 46.2125L23.8484 46.2132C22.6114 46.6734 21.1799 46.9091 19.5455 46.9091C17.899 46.9091 16.4895 46.6592 15.3055 46.1746C14.1338 45.6801 13.275 44.9649 12.7004 44.0364C12.1501 43.1082 11.9297 41.9221 12.0881 40.4395L12.1472 39.8864H11.5909H2.06818H1.63342L1.57303 40.3169C1.09359 43.7348 1.44198 46.6566 2.66881 49.0465L2.67066 49.0501C3.9107 51.4189 5.88799 53.1969 8.56966 54.3887C11.2417 55.5763 14.4896 56.1591 18.2955 56.1591C22.1325 56.1591 25.5303 55.5836 28.479 54.4196L28.4812 54.4188C31.4248 53.2413 33.8209 51.5836 35.6529 49.4383L35.6541 49.437C37.488 47.2739 38.653 44.7203 39.152 41.7884L39.1525 41.7855C39.4798 39.7907 39.4223 37.9928 38.9571 36.4049C38.4953 34.8282 37.6968 33.4539 36.564 32.2888C35.457 31.1347 34.0885 30.1701 32.4673 29.3906C30.8697 28.6152 29.0779 27.9982 27.0946 27.5367L23.0985 26.5377L23.0985 26.5376L23.0931 26.5363C22.1586 26.3138 21.2783 26.0475 20.452 25.7378C19.638 25.4177 18.9432 25.0511 18.3626 24.6413C17.82 24.2331 17.4319 23.761 17.1831 23.2262C16.9627 22.7212 16.9073 22.104 17.0585 21.3481L17.0602 21.3396L17.0616 21.331C17.2125 20.4117 17.6012 19.6058 18.2346 18.9034C18.8836 18.1854 19.7583 17.6125 20.8788 17.1959L20.8788 17.196L20.884 17.1939C21.9955 16.7665 23.3259 16.5454 24.8864 16.5454C27.1892 16.5454 28.8128 17.0489 29.8508 17.9657L29.8533 17.9678C30.8968 18.8776 31.4124 20.1797 31.3413 21.9573Z"
stroke="#ffffff"
/>
<path
d="M59.7045 8.37895L59.6396 7.95454H59.2102H48.2784H47.6808L47.7862 8.54274L56.1272 55.0882L56.201 55.5H56.6193H69.3011H69.6072L69.7464 55.2274L93.5192 8.68197L93.8907 7.95454H93.0739H82.1648H81.8513L81.7147 8.23674L64.974 42.8298L59.7045 8.37895Z"
stroke="#ffffff"
/>
<path
d="M123.918 23.5545L123.967 24H124.415H134.415H134.902L134.915 23.5131C134.977 21.1479 134.596 18.971 133.763 16.9899C132.947 14.9976 131.737 13.2775 130.137 11.8341C128.553 10.3915 126.653 9.2837 124.446 8.50636C122.248 7.7115 119.804 7.31818 117.119 7.31818C113.999 7.31818 110.992 7.86687 108.101 8.96437L108.1 8.96469C105.224 10.0626 102.604 11.663 100.242 13.7627C97.8763 15.8652 95.879 18.4276 94.2477 21.444L94.2473 21.4448C92.6268 24.4542 91.5049 27.8717 90.876 31.6915L90.8759 31.692C90.0635 36.6583 90.2791 40.9889 91.5561 44.6641L91.557 44.6665C92.8486 48.3235 95.0282 51.1652 98.0959 53.1686L98.0984 53.1702C101.181 55.1573 104.954 56.1364 109.392 56.1364C113.385 56.1364 117.065 55.3343 120.426 53.724C123.802 52.1134 126.622 49.804 128.882 46.8007C131.149 43.7889 132.609 40.196 133.272 36.036C133.272 36.035 133.272 36.0341 133.272 36.0332L134.271 30.175L134.371 29.5909H133.778H114.301H113.877L113.808 30.0092L112.581 37.4183L112.484 38H113.074H122.431C122.07 39.5401 121.432 40.8895 120.521 42.0558L120.519 42.0584C119.451 43.4438 118.071 44.5225 116.369 45.2938C114.67 46.0489 112.741 46.4318 110.574 46.4318C108.201 46.4318 106.309 45.862 104.855 44.7622C103.417 43.6475 102.417 42.0202 101.878 39.8364C101.353 37.6502 101.347 34.9652 101.885 31.7648L101.885 31.7625C102.407 28.5731 103.379 25.8994 104.789 23.7266L104.79 23.7253C106.206 21.5264 107.908 19.8667 109.89 18.7296C111.891 17.5908 114.032 17.0227 116.324 17.0227C117.541 17.0227 118.591 17.1768 119.484 17.4743C120.38 17.7731 121.128 18.2023 121.738 18.7563L121.738 18.7564L121.742 18.7605C122.352 19.3007 122.833 19.9676 123.184 20.769L123.184 20.7691L123.189 20.7787C123.556 21.5696 123.801 22.4925 123.918 23.5545Z"
stroke="#ffffff"
/>
<path
d="M168.067 14.052H167.567V14.552V20.004H167.299H138.883H138.383V20.504V27.416V27.916H138.883H146.261C144.792 34.47 142.715 40.6478 141.946 42.4451C141.405 43.6213 140.926 44.5436 140.444 45.2222C139.96 45.9017 139.505 46.2919 139.03 46.4668L138.528 46.6519L138.747 47.1405C139.567 48.9712 140.774 52.465 141.151 53.9102L141.21 53.9027L141.296 54.631L141.967 54.2064C142.867 53.6362 144.045 53.0918 147.444 52.0625C150.304 51.1965 154.707 49.9952 161.797 48.1471C162.036 49.0658 162.238 49.9197 162.393 50.6834L162.504 51.2289L163.034 51.0606L167.869 49.5266C166.718 51.3122 165.378 52.9551 163.818 54.4465L163.359 54.8845L163.892 55.2281C165.804 56.4618 168.254 59.0944 169.507 60.9733L169.844 61.4782L170.275 61.0513C172.803 58.5488 174.841 55.7016 176.485 52.5556L176.541 52.6444C177.829 54.6677 178.645 57.8465 178.833 59.9719L178.872 60.4104L179.311 60.4276C182.568 60.5553 185.883 60.5592 187.994 60.1644C189.174 59.9674 190.183 59.6819 191.103 59.1436C192.027 58.6032 192.829 57.8277 193.626 56.6987C194.229 55.8639 194.694 54.6334 195.076 52.9006C195.46 51.1585 195.768 48.8638 196.029 45.8673C196.551 39.874 196.887 31.0111 197.239 18.0215L197.239 18.0215V18.008C197.239 17.5663 197.255 16.708 197.271 15.9546C197.279 15.5791 197.287 15.2315 197.293 14.9778L197.3 14.6759L197.302 14.5933L197.303 14.5718L197.303 14.5663L197.303 14.5649L197.303 14.5646L197.303 14.5645L197.316 14.052H196.803H193.719H193.219H189.251H188.751H183.309C183.388 10.0839 183.404 5.99644 183.415 1.81728L183.416 1.31599H182.915H175.363H174.864L174.863 1.8146C174.861 2.62833 174.859 3.4368 174.857 4.23984C174.85 7.60996 174.843 10.8845 174.796 14.052H168.067ZM167.799 27.416V22.412H168.067H174.54C174.353 26.0327 174.052 29.4777 173.565 32.7257C172.791 37.8767 171.549 42.508 169.556 46.5403C168.312 42.1015 165.988 36.0135 163.917 31.3104L163.742 30.9131L163.324 31.0307L157.18 32.7587L156.643 32.9096L156.851 33.4266C157.759 35.6843 158.698 38.2348 159.552 40.7609L150.185 42.965C152.083 38.2753 153.867 32.995 155.162 27.916H167.299H167.799V27.416ZM177.015 51.8787L176.839 51.8604C179.179 47.1569 180.677 41.8109 181.64 35.9694C182.343 31.7068 182.763 27.1694 183.017 22.412H188.609C188.387 31.2851 188.133 37.7219 187.792 42.2747C187.585 45.0523 187.347 47.1147 187.068 48.5955C186.785 50.0966 186.474 50.9148 186.177 51.2906C185.859 51.6649 185.582 51.8795 185.295 52.0075C185.006 52.1368 184.666 52.196 184.195 52.196C182.789 52.196 180.059 52.1958 177.015 51.8787ZM140.995 5.092H140.495V5.592V12.376V12.876H140.995H166.211H166.711V12.376V5.592V5.092H166.211H140.995Z"
stroke="#ffffff"
/>
<path
d="M212.983 49.252V15.896V15.396H212.483H205.059H204.559V15.896V60.76V61.26H205.059H212.483H212.983V60.76V57.484H250.767V60.696V61.196H251.267H258.755H259.255V60.696V15.896V15.396H258.755H251.267H250.767V15.896V49.252H212.983ZM203.075 4.004H202.575V4.504V11.672V12.172H203.075H227.215V16.292H216.515H216.015V16.792V46.04V46.54H216.515H247.107H247.607V46.04V16.792V16.292H247.107H236.023V12.172H260.739H261.239V11.672V4.504V4.004H260.739H203.075ZM223.351 23.564H227.855V27.94H223.351V23.564ZM223.351 34.828H227.855V39.268H223.351V34.828ZM240.015 39.268H235.447V34.828H240.015V39.268ZM240.015 27.94H235.447V23.564H240.015V27.94Z"
stroke="#ffffff"
/>
</svg>

<script>
const logo = document.querySelectorAll('.logo path');
for (let i = 0; i < logo.length; i++) {
console.log(`${i}`, logo[i].getTotalLength());
}
</script>
</body>
</html>