Open Marinerer opened 3 years ago
源自:https://www.ruanyifeng.com/blog/2018/08/svg.html
参考:MDN SVG教程
贝塞尔曲线 - 维基百科
[TOC]
SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics)。其他图像格式都是基于像素处理的,SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
- SVG 文件可以直接插入网页,成为 DOM 的一部分,然后用 JavaScript 和 CSS 进行操作。
- SVG 代码也可以写在一个独立文件中,然后用
<img>
、<object>
、<embed>
、<iframe>
等标签插入网页。- CSS 也可以使用 SVG 文件
- SVG 文件还可以转为 BASE64 编码,然后作为 Data URI 写入网页
<html>
<head>SVG</head>
<body>
<!--直接插入svg代码-->
<svg width="300" height="180">
<circle cx="30" cy="50" r="25" />
</svg>
<!--独立文件插入-->
<img src="circle.svg">
<object id="object" data="circle.svg" type="image/svg+xml"></object>
<embed id="embed" src="icon.svg" type="image/svg+xml">
<iframe id="iframe" src="icon.svg"></iframe>
<!--base64-->
<img src="data:image/svg+xml;base64,[data]">
<!--css中引入-->
<style>
.logo {
background: url(icon.svg);
}
</style>
</body>
</html>
<svg>
标签SVG 代码都放在顶层标签<svg>
之中。下面是一个例子。
<svg width="450" height="400" viewBox="0 0 450 400" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path id="lineAB" d="M 100 350 l 150 -300" stroke="red" stroke-width="3" fill="none" />
<path id="lineBC" d="M 250 50 l 150 300" stroke="red" stroke-width="3" fill="none" />
<path d="M 175 200 l 150 0" stroke="green" stroke-width="3" fill="none" />
<path d="M 100 350 q 150 -300 300 0" stroke="blue" stroke-width="5" fill="none" />
<!-- Mark relevant points -->
<g stroke="black" stroke-width="3" fill="black">
<circle id="pointA" cx="100" cy="350" r="3" />
<circle id="pointB" cx="250" cy="50" r="3" />
<circle id="pointC" cx="400" cy="350" r="3" />
</g>
<!-- Label the points -->
<g font-size="30" font-family="sans-serif" fill="black" stroke="none" text-anchor="middle">
<text x="100" y="350" dx="-30">A</text>
<text x="250" y="50" dy="-10">B</text>
<text x="400" y="350" dx="30">C</text>
</g>
Sorry, your browser does not support inline SVG.
</svg>
<svg>
的width
属性和height
属性,指定了 SVG 图像在 HTML 元素中所占据的宽度和高度。除了相对单位,也可以采用绝对单位(单位:像素)。如果不指定这两个属性,SVG 图像默认大小是300像素(宽) x 150像素(高)。
如果只想展示 SVG 图像的一部分,就要指定viewBox
属性。
<svg width="100" height="100" viewBox="50 50 50 50">
<circle id="mycircle" cx="50" cy="50" r="50" />
</svg>
<viewBox>
属性的值有四个数字,分别是左上角的横坐标和纵坐标、视口的宽度和高度。上面代码中,SVG 图像是100像素宽 x 100像素高,viewBox
属性指定视口从(50, 50)
这个点开始。所以,实际看到的是右下角的四分之一圆。
注意,视口必须适配所在的空间。上面代码中,视口的大小是 50 x 50,由于 SVG 图像的大小是 100 x 100,所以视口会放大去适配 SVG 图像的大小,即放大了四倍。
如果不指定width
属性和height
属性,只指定viewBox
属性,则相当于只给定 SVG 图像的长宽比。这时,SVG 图像的默认大小将等于所在的 HTML 元素的大小。
<circle>
圆形<circle>
标签代表圆形。
<svg width="300" height="180">
<circle cx="30" cy="50" r="25" />
<circle cx="90" cy="50" r="25" class="red" />
<circle cx="150" cy="50" r="25" class="fancy" />
</svg>
上面的代码定义了三个圆。<circle>
标签的cx
、cy
、r
属性分别为横坐标、纵坐标和半径,单位为像素。坐标都是相对于<svg>
画布的左上角原点。
class
属性用来指定对应的 CSS 类。
.red {
fill: red;
}
.fancy {
fill: none;
stroke: black;
stroke-width: 3pt;
}
SVG 的 CSS 属性与网页元素有所不同。
fill
:填充色stroke
:描边色stroke-width
:边框宽度stroke-linecap
:控制边框终点的形状
butt
用直边结束线段,它是常规做法,线段边界90度垂直于描边的方向、贯穿它的终点。square
的效果差不多,但是会稍微超出实际路径
的范围,超出的大小由stroke-width
控制。round
表示边框的终点是圆角,圆角的半径也是由stroke-width
控制的。stroke-linejoin
:控制两条描边线段之间,用什么样式连接 ,比如尖角、圆弧、横切
miter
round
bevel
<line>
直线<line>
标签用来绘制直线。
<svg width="300" height="180">
<line x1="0" y1="0" x2="200" y2="0" style="stroke:rgb(0,0,0);stroke-width:5" />
</svg>
上面代码中,<line>
标签的x1
属性和y1
属性,表示线段起点的横坐标和纵坐标;x2
属性和y2
属性,表示线段终点的横坐标和纵坐标;style
属性表示线段的样式。
<polyline>
折线<polyline>
标签用于绘制一根折线。
<svg width="300" height="180">
<polyline points="3,3 30,28 3,53" fill="none" stroke="black" />
</svg>
<polyline>
的points
属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。
<rect>
矩形<rect>
标签用于绘制矩形。
<svg width="300" height="180">
<rect x="0" y="0" height="100" width="200" rx="10" ry="10" style="stroke: #70d5dd; fill: #dd524b" />
</svg>
<rect>
的x
属性和y
属性,指定了矩形左上角端点的横坐标和纵坐标;width
属性和height
属性指定了矩形的宽度和高度(单位像素)。
rx
和 ry
属性可以创建圆角矩形,rx
定义水平轴向的圆角半径,ry
定义垂直轴向的圆角半径。
<ellipse>
椭圆<ellipse>
标签用于绘制椭圆。
<svg width="300" height="180">
<ellipse cx="60" cy="60" ry="40" rx="20" stroke="black" stroke-width="5" fill="silver"/>
</svg>
<ellipse>
的cx
属性和cy
属性,指定了椭圆中心的横坐标和纵坐标(单位像素);rx
属性和ry
属性,指定了椭圆横向轴和纵向轴的半径(单位像素)。
<polygon>
多边形<polygon>
标签用于绘制多边形。
<svg width="300" height="180">
<polygon fill="green" stroke="orange" stroke-width="1" points="0,0 100,0 100,100 0,100 0,0"/>
</svg>
<polygon>
的points
属性指定了每个端点的坐标,横坐标与纵坐标之间与逗号分隔,点与点之间用空格分隔。
<path>
路径<path>
标签用于制路径。
<svg width="90" height="90">
<path d="
M 18,3
L 46,3
L 46,40
L 61,40
L 32,68
L 3,40
L 18,40
Z
" fill="blue" />
</svg>
<svg width="90" height="90">
<path d="
M60,30
a30,30 0 0,1 0,60
L0,90 0,30
a30,30 0 0,1 60,0" fill="red" />
</svg>
<svg width="90" height="90">
<path d="
M75,45
a30,30 0 0,1 -60,0
a30,30 0 0,1 60,0" stroke-width="1" stroke="blue" fill="none"/>
</svg>
<path>
的d
属性表示绘制顺序,它的值是一个长字符串,每个字母表示一个绘制动作,后面跟着坐标。
- M:移动到(moveto)
- L:画直线到(lineto)
- Z:闭合路径
- A:弧形
- C:贝塞尔曲线
Path相关指令:
先罗列一下有关于<path>
元素相关的指令:
⚠️ 特别注意: 参数大写代表绝对坐标,小写代表与前一个坐标的相对座标。
指令 | 参数 | 描述 |
---|---|---|
M |
x y |
起始点坐标x y (Move to ) |
L |
x y |
从当前点的坐标画直线到指定点的 x y 坐标 (Line to ) |
H |
x |
从当前点的坐标画水平直线到指定的x 轴坐标 (Horizontal line to ) |
V |
y |
从当前点的座标画垂直直线到指定的y 轴坐标 (Vertical line to ) |
C |
x1 y1 x2 y2 x y |
从当前点的坐标画条贝塞尔曲线到指定点的x, y 坐标,其中 x1 y1 及x2, y2 为控制点 (Curve ) |
S |
x2 y2 x y |
从当前点的坐标画条反射的贝塞曲线到指定点的x, y 坐标,其中x2, y2 为反射的控制点(Smooth curve ) |
Q |
x1 y1 x y |
从当前点的坐标画条反射二次贝塞曲线到指定点的x, y 坐标,其中x1 y1 为控制点(Quadratic Bézier curve ) |
T |
x y |
从当前点的坐标画条反射二次贝塞曲线到指定点的x, y 坐标,以前一个坐标为反射控制点(Smooth Quadratic Bézier curve ) |
A |
rx ry x-axis-rotation large-arc-flag sweep-flag x y |
从当前点的坐标画个椭圆形到指定点的x, y 坐标,其中rx, ry 为椭圆形的x 轴及y 轴的半径,x-axis-rotation 是弧线与x 轴的旋转角度,large-arc-flag 则设定1 最大角度的弧线或是0 最小角度的弧线,sweep-flag 设定方向为1 顺时针方向或0 逆时针方向(Arc ) |
Z |
关闭路径,将当前点坐标与第一个点的坐标连接起来(Closepath ) |
<text>
文本<text>
标签用于绘制文本。
<svg height="200" width="200">
<text x="10" y="20" style="fill:red;" font-weight="bold">Several lines:
<tspan x="24" y="45">First line.</tspan>
<tspan x="24" y="70">Second line.</tspan>
</text>
</svg>
<text>
的x
属性和y
属性,表示文本区块基线(baseline)起点的横坐标和纵坐标。文字的样式可以用class
或style
属性指定。
设置字体属性:
SVG提供了一些属性,类似于它们的CSS同行,用来激活文本选区。下列每个属性可以被设置为一个SVG属性或者成为一个CSS声明:font-family
、font-style
、font-weight
、font-variant
、font-stretch
、font-size
、font-size-adjust
、kerning
、letter-spacing
、word-spacing
和text-decoration
。
文本相关的元素:
tspan
: 用来标记大块文本的子部分,它必须是一个text
元素或别的tspan
元素的子元素。tref
: 允许引用已经定义的文本,高效地把它复制到当前位置。你可以使用xlink:href
属性,把它指向一个元素,取得其文本内容。你可以独立于源样式化它、修改它的外观。textPath
: 该元素利用它的xlink:href
属性取得一个任意路径,把字符对齐到路径,于是字体会环绕路径、顺着路径走。<use>
标签<use>
标签用于复制一个形状。
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
<circle id="myCircle" cx="5" cy="5" r="4"/>
<use href="#myCircle" x="10" y="0" fill="blue" />
<use href="#myCircle" x="20" y="0" fill="white" stroke="blue" />
</svg>
<use>
的href
属性指定所要复制的节点,x
属性和y
属性是<use>
左上角的坐标。另外,还可以指定width
和height
坐标。
<g>
组<g>
标签用于将多个形状组成一个组(group),方便复用。
<svg width="300" height="100">
<g id="myCircle">
<text x="25" y="20">圆形</text>
<circle cx="50" cy="50" r="20"/>
</g>
<use href="#myCircle" x="100" y="0" fill="blue" />
<use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>
<defs>
标签<defs>
标签用于自定义形状,它内部的代码不会显示,仅供引用。
<svg width="300" height="100">
<defs>
<g id="myCircle">
<text x="25" y="20">圆形</text>
<circle cx="50" cy="50" r="20"/>
</g>
</defs>
<use href="#myCircle" x="0" y="0" />
<use href="#myCircle" x="100" y="0" fill="blue" />
<use href="#myCircle" x="200" y="0" fill="white" stroke="blue" />
</svg>
<pattern>
标签<pattern>
标签用于自定义一个形状,该形状可以被引用来平铺一个区域。
<svg width="500" height="500">
<defs>
<pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
<circle fill="#bee9e8" cx="50" cy="50" r="35" />
</pattern>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="url(#dots)" />
</svg>
上面代码中,<pattern>
标签将一个圆形定义为dots
模式。patternUnits="userSpaceOnUse"
表示<pattern>
的宽度和长度是实际的像素值。然后,指定这个模式去填充下面的矩形。
<image>
图片<image>
标签用于插入图片文件。
<svg viewBox="0 0 100 100" width="100" height="100">
<image xlink:href="path/to/image.jpg"
width="50%" height="50%"/>
</svg>
上面代码中,<image>
的xlink:href
属性表示图像的来源。
<animate>
动画<animate>
标签用于产生动画效果。
<svg width="500px" height="500px">
<rect x="0" y="0" width="100" height="100" fill="#feac5e">
<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
</rect>
</svg>
上面代码中,矩形会不断移动,产生动画效果。
<animate>
的属性含义如下。
- attributeName:发生动画效果的属性名。
- from:单次动画的初始值。
- to:单次动画的结束值。
- dur:单次动画的持续时间。
- repeatCount:动画的循环模式。
可以在多个属性上面定义动画。
<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
<animate attributeName="width" to="500" dur="2s" repeatCount="indefinite" />
<animateTransform>
变形动画<animate>
标签对 CSS 的transform
属性不起作用,如果需要变形,就要使用<animateTransform>
标签。
<svg width="500px" height="500px">
<rect x="250" y="250" width="50" height="50" fill="#4bc0c8">
<animateTransform
attributeName="transform"
type="rotate"
begin="0s"
dur="10s"
from="0 200 200"
to="360 400 400"
repeatCount="indefinite"
/>
</rect>
</svg>
上面代码中,<animateTransform>
的效果为旋转(rotate
),这时from
和to
属性值有三个数字,第一个数字是角度值,第二个值和第三个值是旋转中心的坐标。from="0 200 200"
表示开始时,角度为0,围绕(200, 200)
开始旋转;to="360 400 400"
表示结束时,角度为360,围绕(400, 400)
旋转。
<animateMotion>
路径动画<animateMotion>
元素可以定义一个元素沿着指定路径进行移动。
from + to
属性来指定起点和终点;path
指定复杂的路径;<path>
元素作为自己的路径注意:为了复用一个已经定义的路径,就有必要使用一个
mpath
元素嵌入到<animateMotion>
中,而不是使用path
。例如:
<mpath xlink:href="#cubicCurve"/>
<svg viewBox="0 0 200 100">
<path id="cubicCurve" fill="none" stroke="lightgrey" d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />
<circle r="5" fill="red">
<animateMotion
dur="10s"
repeatCount="indefinite"
path="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z"
/>
</circle>
<rect x="0" y="0" width="10" height="10" fill="blue">
<animateMotion dur="20" repeatCount="indefinite">
<mpath xlink:href="#cubicCurve" />
</animateMotion>
</rect>
</svg>
<animateMotion>
有个rotate
属性,默认为0,元素在运动时不会旋转。当设置为auto时,元素对应的水平轴会始终与path路径保持水平,上图中加上rotate="auto"后的效果就像是车子开过山坡。
<linearGradient>
线性渐变渐变有两种类型:
线性渐变
和径向渐变
。你必须给渐变内容指定一个id属性,否则文档内的其他元素就不能引用它。为了让渐变能被重复使用,渐变内容需要定义在<defs>
标签内部,而不是定义在形状上面。
线性渐变沿着直线改变颜色,要插入一个线性渐变,你需要在SVG文件的defs元素内部,创建一个<linearGradient>
节点。
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="Gradient1">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="50%"/>
<stop class="stop3" offset="100%"/>
</linearGradient>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="red"/>
<stop offset="50%" stop-color="black" stop-opacity="0"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<style type="text/css"><![CDATA[
#rect1 { fill: url(#Gradient1); }
.stop1 { stop-color: red; }
.stop2 { stop-color: black; stop-opacity: 0; }
.stop3 { stop-color: blue; }
]]></style>
</defs>
<rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100"/>
<rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>
</svg>
<radialGradient>
径向渐变<?xml version="1.0" standalone="no"?>
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="RadialGradient1">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
<radialGradient id="RadialGradient2" cx="0.25" cy="0.25" r="0.25">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#RadialGradient1)"/>
<rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#RadialGradient2)"/>
</svg>
<clipPath>
剪切我们在一个圆形的基础上创建半圆形,在(100,100)
创建一个圆形,半径是100。属性clip-path
引用了一个带单个rect元素的<clipPath>
元素。它内部的这个矩形将把画布的上半部分涂黑。注意,clipPath
元素经常放在一个defs
元素内。
<svg version="1.1">
<defs>
<clipPath id="cut-off-bottom">
<rect x="0" y="0" width="200" height="100" />
</clipPath>
</defs>
<circle cx="100" cy="100" r="100" clip-path="url(#cut-off-bottom)" />
</svg>
<mask>
遮罩遮罩的效果最令人印象深刻的是表现为一个渐变。如果你想要让一个元素淡出,你可以利用遮罩效果实现。
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="Gradient">
<stop offset="0" stop-color="white" stop-opacity="0" />
<stop offset="1" stop-color="white" stop-opacity="1" />
</linearGradient>
<mask id="Mask">
<rect x="0" y="0" width="200" height="200" fill="url(#Gradient)" />
</mask>
</defs>
<rect x="0" y="0" width="200" height="200" fill="green" />
<rect x="0" y="0" width="200" height="200" fill="red" mask="url(#Mask)" />
</svg>
<filter>
滤镜见 https://developer.mozilla.org/zh-CN/docs/Web/SVG/Tutorial/Filter_effects
以下属性均可以直接用作CSS样式表内部的属性。
fill
: 设置SVG对象内部的填充色。可选值:颜色值 | none
fill-rule
: 确定形状内部(即要填充的区域)的算法。 可选值:nonzero | evenodd
fill-opacity
: 控制填充色的不透明度。 可选值:[0-1] | <percentage>
fill-rule
比较难懂,详见 https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-rule
stroke
: 描边颜色stroke-width
: 描边的粗细stroke-linecap
: 描边端点表现方式。可选值:butt | round | square
stroke-linejoin
: 描边转角的表现方式。可选值:miter(尖角) | round(圆角) | bevel(斜角)
stroke-miterlimit
: 描边相交(锐角)的表现方式。默认大小是4
stroke-miterlimit
属性给miter-length
和stroke-width
之间的比率做了限制,它的比值范围应大于或等于1。当比值不在这个范围的时候, stroke 就会被转换成斜角(bevel)。
stroke-dasharray
: 设置虚线描边。可选值为:none | <dasharray>
stroke-dashoffset
: 虚线的起始偏移。可选值为:<percentage> | <length>
stroke-opacity
: 描边透明度。默认是1
stroke-dasharray
和stroke-dashoffset
可用于实现描边动画。
🌰 心形路径动画例子:
<svg class="heart" width="90" height="90" viewBox="0 0 90 90">
<g class="heart-group">
<path class="heart-heartPath" stroke-width="2" d="M60,30 a30,30 0 0,1 0,60 L0,90 0,30 a30,30 0 0,1 60,0" />
</g>
</svg>
<style>
.heart {
margin: 90px;
overflow: visible;
&-group {
transform-origin: 0 90px;
transform: rotate(-45deg);
animation: group-anim 4s infinite;
}
&-heartPath {
stroke: #E21737;
fill: transparent;
stroke-dasharray: 308.522, 308.522;
stroke-dashoffset: 308.522;
animation: heart-anim 4s infinite;
}
}
@keyframes group-anim {
0%, 100% {
opacity: 0;
}
40%, 90% {
opacity: 1;
}
}
@keyframes heart-anim {
15% {
stroke-dashoffset: 308.522;
fill: transparent;
}
50% {
stroke-dashoffset: 0;
fill: transparent;
}
70%, 100% {
stroke-dashoffset: 0;
fill: #E21737;
}
}
</style>
vector-effect
vector-effect
指定绘制对象时要使用的矢量效果。矢量效果会先于其他任何合成操作(即滤镜,蒙版和剪辑)应用。
可选值:
none
|non-scaling-stroke
|non-scaling-size
|non-rotation
|fixed-position
最常用的就是non-scaling-stroke
,指定描边宽度不随SVG本身尺寸变大而变大。
如果 SVG 代码直接写在 HTML 网页之中,它就成为网页 DOM 的一部分,可以直接用 DOM 操作。
<svg
id="mysvg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 800 600"
preserveAspectRatio="xMidYMid meet"
>
<circle id="mycircle" cx="400" cy="300" r="50" />
<svg>
上面代码插入网页之后,就可以用 CSS 定制样式。
circle {
stroke-width: 5;
stroke: #f00;
fill: #ff0;
}
circle:hover {
stroke: #090;
fill: #fff;
}
然后,可以用 JavaScript 代码操作 SVG。
var mycircle = document.getElementById('mycircle');
mycircle.addEventListener('click', function(e) {
console.log('circle clicked - enlarging');
mycircle.setAttribute('r', 60);
}, false);
上面代码指定,如果点击图形,就改写circle
元素的r
属性。
使用<object>
、<iframe>
、<embed>
标签插入 SVG 文件,可以获取 SVG DOM。
var svgObject = document.getElementById('object').contentDocument;
var svgIframe = document.getElementById('iframe').contentDocument;
var svgEmbed = document.getElementById('embed').getSVGDocument();
注意,如果使用<img>
标签插入 SVG 文件,就无法获取 SVG DOM。
由于 SVG 文件就是一段 XML 文本,因此可以通过读取 XML 代码的方式,读取 SVG 源码。
<div id="svg-container">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:space="preserve" width="500" height="440"
>
<!-- svg code -->
</svg>
</div>
使用XMLSerializer
实例的serializeToString()
方法,获取 SVG 元素的代码。
var svgString = new XMLSerializer()
.serializeToString(document.querySelector('svg'));
源自:https://segmentfault.com/a/1190000009371194
参考: https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/
[toc]
<animate>
基本动画<animate>
元素用于实现动画效果。
可以将<animate>
元素嵌入到元素内,来实现该元素的动画效果。
<rect x="10" y="10" width="200" height="20" stroke="black" fill="none">
<animate
attributeName="width"
attributeType="XML"
from="200"
to="20"
begin="0s"
dur="5s"
fill="freeze"
/>
</rect>
以上代码会生成一个200x20
的长方形,在5秒内渐变成一个20x20
的正方形,并且在动画结束时停留在正方形的状态。
<attributeName>
定义发生变化的元素属性名
<ellipse>
元素的cx
或cy
; opacity
CSS | XML | auto
当attributeType="XML"
时,attributeName被认为是XML的属性;当attributeType="CSS"
时,attributeName被认为是css的属性;不指定attributeType时,默认为"auto",会先将attributeName作为css的属性,如果无效,再将attributeName作为XML的属性。
例如 x
, y
以及transform
就属于XML
, opacity
就属于CSS
。
上面4个属性是一个家族的,他们要解决的问题:你从哪里来?要到哪里去?...
<value>
: 动画的起始值<value>
: 指定动画的结束值<value>
: 动画的相对变化值<list>
: 用分号分隔的一个或多个值,可用于多节点动画from
, to
, by
, values
虽然属于一个家族,但是相互之间还是有制约关系的。有以下一些规则:
from
参数可以省略。values
)to
,by
两个参数至少需要有一个出现。否则动画效果没有。to
表示绝对值,by
表示相对值。拿位移距离,如果from
是100
, to
值为160
则表示移动到160
这个位置,但是,如果by
值是160
,则表示移动到100+160=260
这个位置。to
,by
同时出现,则by
打酱油,只识别to
.to
,by
,values
都没设置,自然没动画效果。如果任意(包括from
)一个属性的值不合法,规范上说是没有动画效果。values
可以是一个值或多值。经测试,是一个值的时候是没有动画效果。多值时候有动画效果。当values
值设置并能识别时候,from
, to
, by
的值都会被忽略。当我们实现动画,不可能就是单纯的从a位置到b位置,有时候,需要去c位置过渡下。此时,实际上有3个动画关键点。而from
, to
/by
只能驾驭两个,此时就可以用values
来实现。<svg viewBox="0 0 10 10">
<rect width="10" height="10">
<animate attributeName="rx" values="0;5;0" dur="10s" repeatCount="indefinite" />
</rect>
</svg>
总结下,也就是from-to
动画、from-by
动画、to
动画、by
动画以及values
动画。
begin
定义动画开始时间;dur
表示单次动画的持续时间;end
定义动画终止时间。时间单位:h:小时;min:分钟;s:秒;ms:毫秒。默认时间单位为s
begin
, end
也可以是分号分隔的一组值(单值只是其中的情况之一)。例如,beigin="3s;5s"
表示的是3s
之后动画走一下,6s
时候动画再走一下(如果之前动画没走完,会立即停止从头开始)。所以,如果一次动画时间为3s
, 即dur="3s"
,同时没有repeatCount
属性时候,我们可以看到动画似乎连续执行了2
次。
begin
的单值除了普通value,还有下面这些类别的value:
offset-value
| syncbase-value
| event-value
| repeat-value
| accessKey-value
| media-marker-value
| wallclock-sync-value
| "indefinite"
详见(https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/)
当fill="freeze"
时,动画终止时,发生变化的元素属性值停留在动画终止时的状态;
当fill="remove"
时,动画终止时,发生变化的元素属性值回复到动画起始时的状态。fill属性默认值为remove
。
允许在同一个元素内嵌入多个
<animate>
<rect x="10" y="10" width="20" height="20" style="stroke: black; fill: #cfc;">
<animate attributeName="width" attributeType="XML" begin="0s" dur="2s" from="20" to="120" fill="freeze"/>
<animate attributeName="height" attributeType="XML" begin="0s" dur="2s" from="20" by="100" fill="freeze"/>
</rect>
有时候我们需要动画能够以它之前的动画结束点作为开始,比如,你需要一个元素的某个属性值一直增加,这个时候我们就需要使用additive和accumulate。
1. accumulate
accumulate
控制动画是否累加,在原来的结果的基础上重复动画的时候,它通常很有用,每一次循环都累加。这个属性告诉动画是否是每次循环,前一个动画属性值要加上去。
- `nonoe` : 重复循环是不累加的。这是默认值。
- `sum` : 表示动画结束时候的位置作为下次动画的起始位置
如果目标属性不支持累加,动画并没有重复,或者是动画仅规定了to属性,这时accumulate会失效。
2. additive
additive
控制动画是否附加。
- `replace` : 默认值,指定动画的基础值将覆盖其他低优先级的动画上。
- `sum` : 表示动画的基础值会附加到其他低优先级的动画上。
<svg width="500" height="500">
<rect x="150" y="150" width="50" height="50" fill="#4bc0c8">
<animateTransform attributeName="transform" type="scale" from="1" to="2" dur="10s" repeatCount="indefinite" additive="sum"/>
<animateTransform attributeName="transform" type="rotate" from="0 100 120" to="360 150 150" dur="10s" fill="freeze" repeatCount="indefinite" additive="sum"/>
</rect>
</svg>
当begin设置为一个具体时间,比如2s
,svg会在元素加载完毕后,过2秒开始执行动画。
begin还可以指定一个其他<animate>
的begin或者end,比如:
<circle cx="60" cy="60" r="30" style="fill: #f9f; stroke: gray;">
<animate id="c1" attributeName="r" attributeType="XML" begin="0s" dur="4s" from="30" to="10" fill="freeze"/>
</circle>
<circle cx="120" cy="60" r="10" style="fill: #9f9; stroke: gray;">
<animate attributeName="r" attributeType="XML" begin="c1.end" dur="4s" from="10" to="30" fill="freeze"/>
</circle>
第二个圆的动画执行起始时间为第一个圆动画执行完毕时间。
begin属性还可以进行简单计算:
begin="c1.end+1.5s"
:表示动画执行起始时间为第一个圆执行完毕后的1.5秒。
当end设置为一个具体时间,比如2s,svg会在元素加载完毕后,过2秒即停止执行动画,不管这个元素的动画是否执行完毕。如果end设置的比begin小,则动画根本不会执行。
end同样可以指定一个其他<animate>
的begin或者end,同样支持计算。
其他参见(https://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/)
通过设置repeatDur
或者repeatCount
属性,让动画重复执行。
repeatDur
: 设置动画执行的总时长。在repeatDur设置的时间内,动画一直会重复执行。如果repeatDur小于dur,repeatDur的作用与end一样。repeatCount
: 设置动画重复执行的次数。repeatDur和repeatCount都可以通过设置为indefinit
实现无限循环动画。
当repeatDur和repeatCount同时作用于同一个<animate>
时,动画终止时间取两者中较小值。
repeat可作为begin和end中的参数使用:
<circle cx="60" cy="60" r="15" style="fill: none; stroke: red;">
<animate id="circleAnim" attributeName="cx" attributeType="XML" begin="0s" dur="5s" repeatCount="3" from="60" to="260" fill="freeze"/>
</circle>
<rect x="230" y="80" width="30" height="30" style="fill: #ccf; stroke: black;">
<animate attributeName="x" attributeType="XML" begin="circleAnim.repeat(1)+2.5s" dur="5s" from="230" to="30" fill="freeze"/>
</rect>
长方形的动画会在圆形动画执行过一遍后延迟2.5秒后开始执行。
repeat(n)中的n需大于0。
实现一个属性的连续变化有两种方式:
<animate>
组合values + keyTimes + calcMode
属性<list>
values属性值表示一个动画经过的节点数值,数值间以分号分割。
<circle cx="175" cy="75" r="20" fill="red">
<animate attributeName="r"
attributeType="XML"
values="20;50;20"
begin="0" dur="1" repeatCount="indefinite"
fill="freeze">
</animate>
</circle>
上例中1秒内,圆的半径由20变为50,再由50变为20。
<list>
keyTimes属性值与values属性值一一对应,第一个数值永远是0(表示起始时间点),最后一个数值永远是1(表示终止时间点),中间的数值表示变化到对应values属性值时所处时间点百分比(0~1之间)。
<circle cx="175" cy="75" r="20" fill="red">
<animate attributeName="r"
attributeType="XML"
values="20;50;20"
keyTimes="0;0.2;1"
begin="0" dur="1" repeatCount="indefinite"
fill="freeze">
</animate>
</circle>
上例中0.2秒时圆的半径由20变为50,在之后的0.8秒又从50变为20。
<calcMode>
calcMode可以影响动画各阶段的表现。calcMode有四种属性值:paced, linear, discrete, spline
calcMode="paced"
时,动画会忽略keyTimes属性,根据values数值以匀速变化。仅支持线性数值区域内的值,这样点之间“距离”的概念才能被计算(如position
, width
, height
等)calcMode="linear"
时,动画根据values和keyTimes属性,在每个时间段内匀速变化。linear为calcMode的默认属性值。calcMode="discrete"
时,动画根据values和keyTimes属性,去掉过渡动画,到了keyTimes的某个节点,属性值直接变为values对应数值。calcMode="spline"
时,需要配合keySplines
属性,设置每个时间段内的三次贝塞尔变化曲线。<circle cx="75" cy="75" r="20" fill="red">
<animate attributeName="r"
attributeType="XML"
values="20;50;20"
keyTimes="0;.15;1"
calcMode="spline" keySplines=".5 0 .5 1;.5 0 .5 1"
begin="0" dur="1" repeatCount="indefinite"
fill="freeze">
</animate>
</circle>
上例中加上贝塞尔曲线后圆形的变化有点类似心跳的节奏。
<list>
keySplines
表示与keyTimes
相关联的一组贝塞尔控制点(默认0 0 1 1
)。每个控制点使用4个浮点值表示:x1 y1 x2 y2
。
只有模式
calcMode = spline
时候这个参数才有用,也是分号分隔,值范围0~1
,总是比keyTimes
少一个值。
如果keySplines
值不合法或个数不对,是没有动画效果的。
<set>
<set>
元素也可设置属性变化的动画,但与<animate>
有明显区别:
style="visibility: hidden;"
<text text-anchor="middle" x="60" y="60" style="visibility: hidden;">
<set attributeName="visibility" attributeType="CSS"
to="visible" begin="1s" dur="10s" fill="freeze"></set>
<set attributeName="x" attributeType="XML"
to="120" begin="2s" dur="10s" fill="freeze"></set>
All gone!
</text>
上例中1秒后显示All gone!,再过1秒后文字移动至(120,60)。
<animateTransform>
变形动画<animate>
标签对 CSS 的transform
属性不起作用, 要实现transform
属性改变的动画,需要使用<animateTransform>
来替代<animate>
。
<rect x="-10" y="-10" width="20" height="20" style="fill: #ff9; stroke: black;">
<animateTransform id="a1" attributeName="transform" attributeType="XML" type="scale" from="1" to="4 2" additive="sum" begin="0s" dur="4s" fill="freeze"></animateTransform>
<animateTransform attributeName="transform" attributeType="XML" type="rotate" from="0" to="45" additive="sum" begin="a1.end" dur="4s" fill="freeze"></animateTransform>
</rect>
<animateTransform>
的attributeName指定为transform
。用type属性指定transform需要改变的属性(translate, scale, rotate, skewX, skewY
)。
<animateTransform>
还有个additive属性。上例中两个<animateTransform>
同时作用于一个<rect>
元素,默认情况下additive属性值为replace
,表示当前<animateTransform>
的初始状态与之前的<animateTransform>
变化结果无关。如果additive="sum"
,表示当前<animateTransform>
的变化基于之前的<animateTransform>
变化之上。
<animateMotion>
路径动画<animateMotion>
元素可以定义一个元素沿着指定路径进行移动。
from + to
属性来指定起点和终点;path
指定复杂的路径;<path>
元素作为自己的路径注意:为了复用一个已经定义的路径,就有必要使用一个
mpath
元素嵌入到<animateMotion>
中,而不是使用path
。例如:
<mpath xlink:href="#cubicCurve"/>
<svg viewBox="0 0 200 100">
<path id="cubicCurve" fill="none" stroke="lightgrey" d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />
<circle r="5" fill="red">
<animateMotion
dur="10s"
repeatCount="indefinite"
path="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z"
/>
</circle>
<rect x="0" y="0" width="10" height="10" fill="blue">
<animateMotion dur="20" repeatCount="indefinite">
<mpath xlink:href="#cubicCurve" />
</animateMotion>
</rect>
</svg>
<animateMotion>
有个rotate
属性,默认为0,元素在运动时不会旋转。当设置为auto时,元素对应的水平轴会始终与path路径保持水平,上图中加上rotate="auto"后的效果就像是车子开过山坡。
与多节点动画中的calcMode属性值及作用完全一致。
第一个属性值为0(表示path路径的起始位置),最后一个属性值为1(表示path路径的终点位置),各属性值用分号分割,每个属性值与keyTimes的属性值一一对应,表示到某个时点运动到相对于路径的哪个位置。
第一个属性值为0(表示动画起始时间),最后一个属性值为1(表示动画终止时间),各属性值用分号分割,每个属性值与keyPoints的属性值一一对应,表示运动到某个位置需要的总动画时常占比。
<path d="M-10,-3 L10,-3 L0,-25z" style="fill: yellow; stroke: red;" >
<animateMotion
path="M50,125 C 100,25 150,225, 200, 125"
rotate="auto"
keyPoints="0;0.2;0.8;1"
keyTimes="0;0.33;0.66;1"
calcMode="linear"
dur="6s" fill="freeze"/>
</path>
css中的两种实现动画方式 transition
和 animation
都可以直接应用于 SVG的DOM元素。
<single-transition> = [ none | <single-transition-property> ] || <time> || <single-transition-timing-function> || <time>
transition-property
: 定义动画属性,可定义多个属性,逗号分隔transition-duration
: 定义动画执行时间,单位(s,ms),可定义多个属性,与transition-property
一一对应,逗号分隔transition-timing-function
: 与calcMode
类似,影响动画的表现。默认值为ease
。transition-delay
: 定义动画延迟多少时间后开始执行.rect{
transition-property:width, height;
transition-duration:1s, 3s;
transition-timing-function: ease-in, cubic-bezier(1,0,0,1);
transition-delay:2s, 0.5s;
}
// 缩写方式
.rect{
transition: width 1s ease-in 2s, height 3s cubic-bezier(1,0,0,1) 0.5s;
}
<single-animation> = <single-animation-name> || <time> || <single-animation-timing-function> || <time> || <single-animation-iteration-count> || <single-animation-direction> || <single-animation-fill-mode> || <single-animation-play-state>
animation-name
: 动画名称,对应<animate>
的attributeName
属性,属性值为@keyframes
名对应animation-duration
: 动画持续时间,对应<animate>
的dur
属性animation-timing-function
: 动画过渡类型,对应<animate>
的calcMode
属性,可用三次贝塞尔曲线来设置动画运行的效果animation-iteration-count
: 动画循环次数,对应<animate>
的repeatCount
属性。默认为1
。infinite
表示无限重复(不同于repeatCount的indefinte)animation-delay
: 动画延迟执行的时间。有点类似<animate>
的start
属性的作用,用start加上一些事件和时间的计算,也可以实现延迟执行动画的效果animation-fill-mode
: 动画时间结束的状态,类似<animate>
的fill
属性,但有区别。animation-fill-mode有四个属性值可选:none | forwards | backwards | both
animation-play-state
: 控制动画的状态,两个属性值 running | paused
animation-direction
: 控制动画是正向运动,或者反向运动,如果设置了animation-iteration-count重复执行次数,还能控制一次动画执行完毕后,以何种方式执行接下去的一次动画。有四个属性值normal | reverse | alternate | alternate-reverse
🌰 心形路径动画例子:
<svg class="heart" width="90" height="90" viewBox="0 0 90 90">
<g class="heart-group">
<path class="heart-heartPath" stroke-width="2" d="M60,30 a30,30 0 0,1 0,60 L0,90 0,30 a30,30 0 0,1 60,0" />
</g>
</svg>
<style>
.heart {
margin: 90px;
overflow: visible;
&-group {
transform-origin: 0 90px;
transform: rotate(-45deg);
animation: group-anim 4s infinite;
}
&-heartPath {
stroke: #E21737;
fill: transparent;
stroke-dasharray: 308.522, 308.522;
stroke-dashoffset: 308.522;
animation: heart-anim 4s infinite;
}
}
@keyframes group-anim {
0%, 100% {
opacity: 0;
}
40%, 90% {
opacity: 1;
}
}
@keyframes heart-anim {
15% {
stroke-dashoffset: 308.522;
fill: transparent;
}
50% {
stroke-dashoffset: 0;
fill: transparent;
}
70%, 100% {
stroke-dashoffset: 0;
fill: #E21737;
}
}
</style>
svgo
是一个用于优化SVG文件的Node.js工具。
因为我们从网上下载或者导出的SVG文件中包含着大量无用的信息,例如编辑源信息,注释以及其它一些不会影响渲染效果但可以去除的信息,这时候可以通过svgo插件,将这些无用的信息进行去除,从而达到优化的效果。该svgo具有基于插件的体系结构,因此几乎每个优化都是一个单独的插件。
npm install svgo --save-dev
⚠️ 注意:
svgo@2.x
版本已不再支持yml
配置文件方式了,仅支持js
配置方式。
创建 src/svgo.config.js
文件
详细参见:https://github.com/svg/svgo/blob/master/README.md#configuration
module.exports = {
multipass: true, // boolean. false by default
datauri: 'enc', // 'base64', 'enc' or 'unenc'. 'base64' by default
js2svg: {
indent: 2, // string with spaces or number of spaces. 4 by default
pretty: true, // boolean, false by default
},
plugins: [
// enable a built-in plugin by name
'builtinPluginName',
// or by expanded version
{
name: 'builtinPluginName',
},
// some plugins allow/require to pass options
{
name: 'builtinPluginName',
params: {
optionName: 'optionValue',
},
},
]
};
{
"svgo": "svgo -f src/icons/svg --config=src/svgo.config.js"
}
-f src/icons/svg
中的-f
表示指定文件夹src/icons/svg
中以.svg
结尾的文件;
-–config=src/svgo.config.js
表定用于扩展或者替换默认值的配置文件;
SVGO基于插件模式构建,基本上所有的优化都是一个分离的插件。
Plugin | Description | Default |
---|---|---|
cleanupAttrs | 清除换行,结束符以及重复空格 | enabled |
mergeStyles | 将多个样式元素合二为一 | enabled |
inlineStyles | 将样式从 <style> 元素移动并合并到元素 style 属性 |
enabled |
removeDoctype | 删除doctype 声明 |
enabled |
removeXMLProcInst | remove XML processing instructions | enabled |
removeComments | 移除 XML 处理指令 | enabled |
removeMetadata | remove <metadata> |
enabled |
removeTitle | remove <title> |
enabled |
removeDesc | remove <desc> |
enabled |
removeUselessDefs | remove elements of <defs> without id |
enabled |
removeXMLNS | removes the xmlns attribute (for inline SVG) |
disabled |
removeEditorsNSData | remove editors namespaces, elements, and attributes | enabled |
removeEmptyAttrs | remove empty attributes | enabled |
removeHiddenElems | remove hidden elements | enabled |
removeEmptyText | remove empty Text elements | enabled |
removeEmptyContainers | remove empty Container elements | enabled |
removeViewBox | 尽可能删除 viewBox 属性 |
enabled |
cleanupEnableBackground | 尽可能删除或清理 enable-background 属性 |
enabled |
minifyStyles | minify <style> elements content with CSSO |
enabled |
convertStyleToAttrs | convert styles into attributes | disabled |
convertColors | convert colors (from rgb() to #rrggbb , from #rrggbb to #rgb ) |
enabled |
convertPathData | 将路径数据转换为的相对路径和绝对路径中简短的那一个,过滤无用的分隔符,智能四舍五入以及其他很多处理 | enabled |
convertTransform | 将多个变换折叠为一个,将矩阵转换为短别名等 | enabled |
removeUnknownsAndDefaults | 移除未知元素内容和属性,移除具有默认值的属性 | enabled |
removeNonInheritableGroupAttrs | 删除不可继承组的presentation 属性 |
enabled |
removeUselessStrokeAndFill | remove useless stroke and fill attributes |
enabled |
removeUnusedNS | 删除未使用的命名空间声明 | enabled |
prefixIds | 使用 SVG 文件名或任意字符串前缀 ID 和类 | disabled |
cleanupIDs | remove unused and minify used IDs | enabled |
cleanupNumericValues | 数值四舍五入提高精度, 删除默认的px 单位 |
enabled |
cleanupListOfValues | 取数字列表的属性中的舍入数值(如viewBox 或enable-background ) |
disabled |
moveElemsAttrsToGroup | 将元素的属性移动到它们的封闭组 | enabled |
moveGroupAttrsToElems | 将一些组属性移动到包含的元素 | enabled |
collapseGroups | collapse useless groups | enabled |
removeRasterImages | 移除光栅图像 | disabled |
mergePaths | 将多个路径合并为一个 | enabled |
convertShapeToPath | 将一些基本形状转换为 <path> |
enabled |
convertEllipseToCircle | 将非偏心 <ellipse> 转换为 <circle> |
enabled |
sortAttrs | 排序元素属性以获得史诗般的可读性 | disabled |
sortDefsChildren | 对 <defs> 的子项进行排序以提高压缩率 |
enabled |
removeDimensions | 删除 width /height 并添加 viewBox 如果它丢失(与 removeViewBox 相反,先禁用它) |
disabled |
removeAttrs | 按模式删除属性 | disabled |
removeAttributesBySelector | 删除与 CSS 选择器匹配的元素的属性 | disabled |
removeElementsByAttr | 通过 ID 或 className 删除任意元素 |
disabled |
addClassesToSVGElement | 将类名添加到外部 <svg> 元素 |
disabled |
addAttributesToSVGElement | 向外部 <svg> 元素添加属性 |
disabled |
removeOffCanvasPaths | 删除在视图框之外绘制的元素 | disabled |
removeStyleElement | remove <style> elements |
disabled |
removeScriptElement | remove <script> elements |
disabled |
reusePaths | 查找重复元素并用链接替换它们 | disabled |
svgo [OPTIONS] [ARGS]
Options:
-h, --help : Help 帮助
-v, --version : Version版本
-i INPUT, --input=INPUT : 输入的文件, "-" 为标准输入
-s STRING, --string=STRING : 输入SVG数据字符串
-f FOLDER, --folder=FOLDER : 输入的文件夹,会优化与重写所有的*.svg文件
-o OUTPUT, --output=OUTPUT : 输入的文件或文件夹 (默认同输入), "-" 标准输出
-p PRECISION, --precision=PRECISION : 设置数字的小数部分,重写插件参数
--config=CONFIG : 配置文件扩展或替换默认设置
--disable=DISABLE : 根据名字禁用插件
--enable=ENABLE : 根据名字开启插件
--datauri=DATAURI : 输入文件以Data URI字符串形式(base64, URI encoded or unencoded)
-q, --quiet : 仅输出错误信息,不包括正常状态消息
--pretty : 让SVG漂亮的打印
--show-plugins : 显示可用和存在的插件
Arguments:
INPUT : 别名 --input
OUTPUT : 别名 --output
文档
工具
教程
SVG基础教程
SVG 入门指南
svg从入门到图标绘制和组件封装
SVG中的Transform详解: 平移,旋转和缩放
SVG动画从入门到实战