一、渐变色和滤镜
1.1 线性渐变
-
SVG除了可以简单的填充和描边,还支持在填充和描边上应用渐变色。渐变有两种类型:线性渐变 和 径向渐变。
- 编写渐变时,必须给渐变内容指定一个 id 属性,use引用需用到。
- 建议渐变内容定义在
<defs>标签内部,渐变通常是可复用的。
-
线性渐变,是沿着直线改变颜色。线性渐变的使用步骤:
-
第1步:在 SVG 文件的 defs 元素内部,创建一个
<linearGradient>节点,并添加 id 属性。 -
第2步:在
<linearGradient>内编写几个<stop>结点。-
给
<stop>结点指定位置 offset属性和 颜色stop-color属性,用来指定渐变在特定的位置上应用什么颜色 -
offset 和 stop-color 这两个属性值,也可以通过 CSS 来指定。
-
也可通过 stop-opacity 来设置某个位置的半透明度。
-
-
第3步:在一个元素的 fill 属性或 stroke 属性中通过ID来引用
<linearGradient>节点。- 比如:属性fill属性设置为url( #Gradient2 )即可。
-
第4步(可选):控制渐变方向,通过 ( x1, y1 ) 和 ( x2, y2 ) 两个点控制。
-
(0, 0) (0, 1)从上到下;(0, 0)(1, 0)从左到右。
-
当然也可以通过 gradientTransform 属性 设置渐变形变。比如:
gradientTransform=“rotate(90)”从上到下。
-
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <!-- 定义可以复用的元素: 样式, 渐变, 图形, 滤镜... --> <defs> <!-- 默认的渐变色 --> <linearGradient id="gradient1"> <stop offset="0%" stop-color="red"></stop> <stop offset="50%" stop-color="green"></stop> <stop offset="100%" stop-color="blue"></stop> </linearGradient> <!-- 改变渐变方向 --> <linearGradient id="gradient2" x1="0" y1="0" x2="1" y2="1"> <stop offset="0%" stop-color="red"></stop> <stop offset="50%" stop-color="green"></stop> <stop offset="100%" stop-color="blue"></stop> </linearGradient> <!-- 通过形变改变渐变方向 --> <linearGradient id="gradient3" gradientTransform="rotate(90)"> <stop offset="0%" stop-color="red"></stop> <stop offset="50%" stop-color="green"></stop> <stop offset="100%" stop-color="blue"></stop> </linearGradient> </defs> <rect x="0" y="0" width="100" height="50" fill="url(#gradient1)"></rect> <rect x="0" y="100" width="100" height="50" fill="url(#gradient2)"></rect> <rect x="0" y="200" width="100" height="50" fill="url(#gradient3)"></rect> </svg> </body> </html> -
1.2 毛玻璃效果(高斯模糊)
1.2.1 css实现
-
backdrop-filter:可以给一个元素后面区域添加模糊效果
- 适用于元素背后的所有元素。为了看到效果,必须使元素或其背景至少部分透明
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; bottom: 0; } .box { position: relative; width: 200px; height: 200px; } .bg-cover { position: absolute; top: 0; left: 0; right: 0; bottom: 0; /* 毛玻璃效果 */ background-color: transparent; backdrop-filter: blur(5px); } </style> </head> <body> <div class="box"> <img src="../images/avatar.jpeg" alt=""> <div class="bg-cover"></div> </div> </body> </html> -
filter:直接将模糊或颜色偏移等模糊效果应用于指定的元素
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; bottom: 0; } .box { position: relative; width: 200px; height: 200px; /* 超出去的模糊效果 隐藏掉 */ overflow: hidden; } img { /* 毛玻璃效果 */ filter: blur(5px); } </style> </head> <body> <div class="box"> <img src="../images/avatar.jpeg" alt=""> </div> </body> </html>
1.2.2 svg实现
-
<filter>:元素作为滤镜操作的容器,该元素定义的滤镜效果需要在SVG元素上的 filter 属性引用。- x ,y, width, height 定义了在画布上应用此过滤器的矩形区域。x, y 默认值为 -10%(相对自身);width ,height 默认值为 120% (相对自身)
-
<feGaussianBlur>:该滤镜专门对输入图像进行高斯模糊- stdDeviation 熟悉指定模糊的程度
-
<feOffset>:该滤镜可以对输入图像指定它的偏移量<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; } </style> </head> <body> <svg width="400" height="200" xmlns="http://www.w3.org/2000/svg" > <defs> <!-- 高斯模糊效果 --> <filter id="blurFilter"> <feGaussianBlur stdDeviation="8"></feGaussianBlur> </filter> <filter id="blurFilter1" x="50%" y="50%" width="100%" height="25%"> <feGaussianBlur stdDeviation="8"></feGaussianBlur> </filter> </defs> <image href="../images/avatar.jpeg" width="200" height="200" filter="url(#blurFilter)" ></image> <image x="200" y="0" href="../images/avatar.jpeg" width="200" height="200" filter="url(#blurFilter1)" ></image> </svg> </body> </html>
二、SVG的形变
-
transform 属性用来定义元素及其子元素的形变的列表。
- 此属性可以与任何一个 SVG 中的元素一起使用
- 从 SVG2 开始,transform它是一个
Presentation Attribute,意味着它可以用作 CSS 属性 - 但是transform作为CSS 属性和元素属性之间的语法会存在一些差异
- 比如作为元素属性时:支持2D变换,不需单位,rotate可指定旋转原点
-
transform属性支持的函数:
- translate(x,y) 平移
- rotate(z) / rotate(z,cx,cy) :旋转
- scale(x, y) :缩放
- skew(x, y) :倾斜
- matrix(a, b, c, d, e) : 2*3 的形变矩阵
-
注意:形变会修改坐标系:形变元素内部会建立一个新的坐标系,后续的绘图或形变都会参照新的坐标系
2.1 translate
-
平移:把元素移动一段距离, 使用transform属性的
translate()函数来平移元素。- 与CSS的translate相似但有区别,这里只支持2D变换,不需单位。
-
translate(x, y)函数
- 一个值时,设置x轴上的平移,而第二个值默认赋值为0
- 二个值时,设置x轴和y轴上的平移
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <!-- 平移一个元素 --> <!-- <rect x="0" y="0" width="100" height="50" transform="translate(100, 100)"></rect> --> <!-- 平移一个元素, 在元素的内部会创建一个新的坐标系统 --> <!-- <rect x="10" y="10" width="100" height="50" transform="translate(100, 100)"></rect> --> <!-- 平移一个元素, 在元素的内部会创建一个新的坐标系统 --> <g transform="translate(100, 100)"> <rect x="10" y="10" width="100" height="50"></rect> </g> </svg> </body> </html>
2.2 rotate
-
旋转:把元素旋转指定的角度, 使用transform属性的
rotate(deg,cx, cy)函数来旋转元素。- 与CSS的rotate相似但有区别。区别是:支持2D变换,不需单位,可指定旋转原点
-
rotate(deg, cx, cy) 函数
- 一个值时,设置z轴上的旋转的角度
-
注意:
- 旋转会修改坐标系,坐标轴也会跟着旋转了
- 如何指定旋转原点?
- 直接在rotate中指定 cx ,cy(相对于自身)
- 使用CSS样式写动画
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <!-- 旋转一个元素 --> <rect x="0" y="0" width="100" height="50" transform="rotate(45, 50, 25) translate(100,50)" ></rect> <!-- 顺序不一致,效果不一致 --> <rect x="0" y="0" width="100" height="50" transform="translate(100,50) rotate(45, 50, 25)" ></rect> </svg> </body> </html>
2.3 scale
-
缩放:改变元素尺寸,使用transform属性的
scale()函数来缩放元素。- 与CSS的scale相似但有区别,这只支持2D变换,不需单位
-
scale(x, y)函数
- 二个值时:它需要两个数字,作为比率计算如何缩放。0.5 表示收缩到 50%
- 一个值时:第二个数字被忽略了,它默认等于第一个值
-
注意:
- 缩放会修改坐标系,坐标轴被缩放了
- 如何指定缩放的原点?
- SVG属性实现需要 平移坐标 和 移动图形
- 直接使用CSS来写动画
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <!-- 缩放一个元素 --> <!-- <rect x="0" y="0" width="100" height="50" transform="translate(100,100) scale(1, 2)" ></rect> --> <!-- 平移坐标,修改原点 --> <!-- <rect x="-25" y="-25" width="50" height="50" transform="translate(100,100) scale(2)" ></rect> --> <!-- 缩放会改变原点 --> <g transform="scale(2)"> <rect x="0" y="0" width="50" height="50" transform="translate(10,0) " ></rect> </g> </svg> </body> </html>
三、描边动画
-
stroke 是描边属性,专门给图形描边。如果想给各种描边添加动画效果,需用到下面两个属性:
-
stroke-dasharray =“number [, number , ….]”: 将虚线类型应用在描边上。 -
该值必须是用逗号分割的数字组成的数列,空格会被忽略。比如 3,5 :
- 第一个表示填色区域的长度为 3
- 第二个表示非填色区域的长度为 5
-
stroke-dashoffset:指定在dasharray模式下路径的偏移量(往左偏移)。- 值为number类型,除了可以正值,也可以取负值。
-
-
描边动画实现步骤:
- 先将描边设置为虚线
- 接着将描边偏移到不可见处
- 通过动画让描边慢慢变为可见,这样就产生了动画效果
3.1 直线的描边
-
不可见 -> 可见
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body, ul{ margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } #line { /* 指定为虚线 */ stroke-dasharray: 100px; /* 可见 */ stroke-dashoffset: 0; animation: lineMove 2s linear; } @keyframes lineMove { 0% { /* 不可见 */ stroke-dashoffset: 100px; } 100% { /* 可见 */ stroke-dashoffset: 0; } } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <line id="line" x1="100" y1="70" x2="200" y2="70" stroke="red" stroke-width="10" > </line> </svg> </body> </html><!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body, ul{ margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } #line { /* 指定为虚线 */ stroke-dasharray: 100px; /* 不可见 */ stroke-dashoffset: 100px; /* 动画结束保持最后一帧的状态 */ animation: lineMove 2s linear forwards; } @keyframes lineMove { 100% { /* 可见 */ stroke-dashoffset: 0; } } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <line id="line" x1="100" y1="70" x2="200" y2="70" stroke="red" stroke-width="10" > </line> </svg> </body> </html> -
如果虚线长度大于线条或者路径的长度,会使动画效果加速
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body, ul{ margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } #line { /* 指定为虚线 长度大于 线条长度 */ stroke-dasharray: 500px; /* 不可见 */ stroke-dashoffset: 500px; /* 动画结束保持最后一帧的状态 */ animation: lineMove 2s linear forwards; } @keyframes lineMove { 100% { /* 可见 */ stroke-dashoffset: 0; } } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <line id="line" x1="100" y1="70" x2="200" y2="70" stroke="red" stroke-width="10" > </line> </svg> </body> </html>
3.2 折线的描边
- 计算出折线的长度即可
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } #line { /* 指定为虚线 */ stroke-dasharray: 130px; /* 不可见 */ stroke-dashoffset: 130px; /* 动画结束保持最后一帧的状态 */ animation: lineMove 2s linear forwards; } @keyframes lineMove { 100% { /* 可见 */ stroke-dashoffset: 0; } } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <path id="line" d="M 100 70, L 200 70, L 200 100" fill="transparent" stroke="red" stroke-width="10" > </path> </svg> </body> </html>
3.3 雪糕的描边
-
实现步骤:
- 找到一个雪糕的SVG图片(设计师提供 | 网站下载)
- 将雪糕的每一个路径都改成虚线
- 将每个路径的描边都移动到虚线的空白处(不可见)
- 给每个路径添加动画,将路径描边慢慢移动到虚线填充处,即可
-
获取路径长度的方法:
<!DOCTYPE html> <html lang="en"> <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" /> <title>Document</title> <style> .outline { stroke-dasharray: 1020px; stroke-dashoffset: 1020px; animation: lineMove 2s linear forwards; } .stick { stroke-dasharray: 500px; stroke-dashoffset: 500px; animation: lineMove 2s linear forwards; animation-delay: 0.5s; } .drop { stroke-dasharray: 200px; stroke-dashoffset: 200px; animation: lineMove 2s linear forwards; animation-delay: 2s; } .inside-l { stroke-dasharray: 800px; stroke-dashoffset: 800px; animation: lineMove 2s linear forwards; animation-delay: 1.5s; } .inside-r { stroke-dasharray: 700px; stroke-dashoffset: 700px; animation: lineMove 2s linear forwards; } @keyframes lineMove { 100% { /* 可见 */ stroke-dashoffset: 0; } } </style> </head> <body> <svg id="popsicle" width="300" height="400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 177.3 449.1" > <g stroke="black" stroke-width="5px"> <!-- 手柄 --> <path class="stick" d="M408.8,395.9V502.4a18.8,18.8,0,0,1-18.8,18.8h0a18.8,18.8,0,0,1-18.8-18.8V415.3" transform="translate(-301.2 -73.5)" fill="none" /> <!-- 水滴 --> <path class="drop" d="M359.1,453.5c0,3.1-2.1,5.6-4.7,5.6s-4.7-2.5-4.7-5.6,2.1-8.3,4.7-8.3S359.1,450.4,359.1,453.5Z" transform="translate(-301.2 -73.5)" fill="none" /> <!-- 外层 --> <path class="outline" d="M389.9,75h0a87.4,87.4,0,0,0-87.2,87.2v218a15.7,15.7,0,0,0,15.7,15.7h12a4.3,4.3,0,0,1,4.1,4.8h0.1v17c0,8.2,9.1,7.9,9.1,0v-6c0-5.2,5.8-5.2,5.8,0v20.5c0,7.7,9.8,7.7,9.8,0V407.2c0-5.2,6.4-5.2,6.4,0v2.7c0,7.7,8.8,7.7,8.8,0v-6c0-6.4,3.9-7.8,6-8.1h80.9a15.7,15.7,0,0,0,15.7-15.7v-218A87.4,87.4,0,0,0,389.9,75Z" transform="translate(-301.2 -73.5)" fill="none" /> <!-- 里面左边 --> <path class="inside-l" d="M55.5,68h0A20.2,20.2,0,0,1,75.7,88.2V276.9a4.5,4.5,0,0,1-4.5,4.5H39.8a4.5,4.5,0,0,1-4.5-4.5V88.2A20.2,20.2,0,0,1,55.5,68Z" fill="none" /> <!-- 里面右边 --> <path class="inside-r" d="M121.8,68h0A20.2,20.2,0,0,1,142,88.2V277a4.4,4.4,0,0,1-4.4,4.4H106.1a4.4,4.4,0,0,1-4.4-4.4V88.2A20.2,20.2,0,0,1,121.8,68Z" fill="none" /> </g> </svg> <script> window.onload = function () { getPathLength("stick"); getPathLength("drop"); getPathLength("outline"); getPathLength("inside-l"); getPathLength("inside-r"); }; function getPathLength(className) { let stickEl = document.getElementsByClassName(className)[0]; // getTotalLength 返回指示路径总长度(以用户单位为单位)的浮点数 let stickLength = stickEl.getTotalLength(); console.log(className + "Length=", stickLength); } </script> </body> </html>
四、SVG中SMIL动画
4.1 SMIL 介绍
-
SMIL(Synchronized Multimedia Integration Language 同步多媒体集成语言)是W3C推荐的可扩展标记语言,用于描述多媒体演示。
-
SMIL 标记是用 XML 编写的,与HTML有相似之处。
-
SMIL 允许开发多媒体项目,例如:文本、图像、视频、音频等。
-
SMIL 定义了时间、布局、动画、视觉转换和媒体嵌入等标记,比如:
<head><body><seq><par><excl>等元素
-
-
SMIL的应用
- 目前最常用的Web浏览器基本都支持 SMIL 语言
- SVG 动画元素是基于SMIL实现(SVG中使用SMIL实现元素有:
<set>、<animate>、<animateMotion>) - Adobe Media Player implement SMIL playback
- QuickTime Player implement SMIL playback
4.2 SVG动画实现方式
-
SVG是一种基于XML的开放标准矢量图形格式,动画可以通过多种方式实现:
-
用JS脚本实现:可以直接通过 JavaScript 在来给 SVG 创建动画和开发交互式的用户界面。
-
用CSS样式实现:自 2008 年以来,CSS动画已成为WebKit中的一项功能,使得我们可以通过CSS动画的方式来给文档对象模型(DOM) 中的 SVG 文件编写动态效果。
-
用SMIL实现:一种基于SMIL语言实现的SVG动画
-
4.3 SMIL动画的优势
-
SVG用SMIL方式实现动画,SMIL允许你做下面这些事情:
- 变动一个元素的数字属性(x、y……)
- 变动变形属性(translation 或 rotation)
- 变动颜色属性
- 物件方向与运动路径方向同步等等
-
SMIL方式实现动画的优势:
-
只需在页面放几个animate元素就可以实现强大的动画效果,无需任何CSS和JS代码
-
SMIL支持声明式动画。声明式动画不需指定如何做某事的细节,而是指定最终结果应该是什么,将实现细节留给客户端软件
-
在 JavaScript 中,动画通常使用 setTimeout() 或 setInterval() 等方法创建,这些方法需要手动管理动画的时间。而SMIL声明式动画可以让浏览器自动处理,比如:动画轨迹直接与动画对象相关联、物体和运动路径方向、管理动画时间等等
-
SMIL 动画还有一个令人愉快的特点是,动画与对象本身是紧密集成的,对于代码的编写和阅读性都非常好
-
4.4 SMIL动画的元素
-
SVG 中支持SMIL动画的元素:
<set><animate><animateColor><animateMotion>- 更多
-
Set
-
<set>元素提供了一种简单的方法,可以在指定的时间内设置属性的值。- set元素是最简单的 SVG 动画元素。它是在经过特定时间间隔后,将属性设置为某个值(不是过度动画效果)。因此,图像不是连续动画,而是改变一次属性值。
- 它支持所有属性类型,包括那些无法合理插值的属性类型,例如:字符串 和 布尔值。而对于可以合理插值的属性通常首选
<animate>元素。
-
<set>元素常用属性:- attributeName:指示将在动画期间更改的目标元素的 CSS 属性( property )或属性( attribute )的名称
attributeType: (已过期) 指定定义目标属性的类型(值为:CSS | XML | auto)- to : 定义在特定时间设置目标属性的值。该值必须与目标属性的要求相匹配。 值类型:;默认值:无
- begin:定义何时开始动画或何时丢弃元素,默认是 0s ( begin支持多种类型的值 )
-
<set>案例:- 1)在3秒后自动将长方形瞬间移到右边
- 2)点击长方形后,长方形瞬间移到右边
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <set attributeName="x" to="200" begin="3"></set> </rect> </svg> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect id="rectangle" x="0" y="0" width="100" height="50" fill="red"> <set attributeName="x" to="200" begin="rectangle.click"></set> </rect> </svg> </body> </html> -
-
Animate
-
<animate>元素给某个属性创建过渡动画效果。需将animate元素嵌套在要应用动画的元素内。 -
<animate>元素常用属性:-
attributeName:指将在动画期间更改目标元素的 property (CSS 属)或 attribute的名称。
-
动画值属性:
- from:在动画期间将被修改的属性的初始值。没有默认值
- to :在动画期间将被修改的属性的最终值。没有默认值
- values:该属性具有不同的含义,具体取决于使用它的上下文(没有默认值)
- 它定义了在动画过度中使用的一系列值,值需要用分号隔开,比如:values=“2 ; 3; 4; 5”
- 当values属性定义时,from、to会被忽略
-
动画时间属性:
- begin:定义何时开始动画或何时丢弃元素。默认是 0s
- dur:动画的持续时间,该值必须,并要求大于 0。单位可以用小时 ( h)、分钟 ( m)、秒 ( s) 或毫秒 ( ms) 表示
- fill:定义动画的最终状态。 freeze(保持最后一个动画帧的状态) | remove(保持第一个动画帧的状态)
- repeatCount:指示动画将发生的次数:
<number>| indefinite。没有默认值
-
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <!-- <animate attributeName="x" from="0" to="200" dur="2s" fill="freeze" repeatCount="2" ></animate> --> <!-- 必须的三个属性 --> <animate attributeName="x" to="200" dur="2s" ></animate> </rect> </svg> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <!-- values 代替 from to --> <animate attributeName="x" values="0; 170; 200" dur="3s" repeatCount="indefinite" ></animate> <animate attributeName="fill" values="skyblue; blue" dur="3s" repeatCount="indefinite" ></animate> </rect> </svg> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="pink"> <animate id="firstAnimate" attributeName="x" values="0; 200" dur="3s" fill="freeze" ></animate> <animate attributeName="y" values="0; 100" dur="3s" fill="freeze" begin="firstAnimate.end" ></animate> </rect> </svg> </body> </html> -
-
AnimateTransform
-
<animateTransform>元素-
指定目标元素的形变(transform)属性,从而允许控制元素的平移、旋转、缩放或倾斜动画(类似于 CSS3 的形变)。
-
在一个动画元素中,只能用一个< animateTransform >元素创建动画;存在多个时,后面会覆盖前面的动画。
-
-
<animateTransform>元素常用属性:-
attributeName:指示将在动画期间更改的目标元素的 CSS 属性( property )或属性( attribute )的名称
-
type :一个指定类型的属性,在不同的使用场景下,有不同的意思:
- 在元素,只支持
translate(x, y) | rotate(deg, cx, cy) | scale(x, y) | skewX(x) | skewY(y) - 在 HTML 中的
<style>和<script>元素,它定义了元素内容的类型
- 在元素,只支持
-
动画值属性:from、to 、values
-
动画时间属性:begin、dur、fill、repeatCount
-
-
平移
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <animateTransform attributeName="transform" type="translate" from="0, 0" to="200, 0" dur="2s" begin="1s" repeatCount="indefinite" ></animateTransform> </rect> </svg> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <animateTransform attributeName="transform" type="translate" values="0, 0; 200, 0" dur="2s" begin="1s" repeatCount="indefinite" ></animateTransform> </rect> </svg> -
旋转
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <animateTransform attributeName="transform" type="rotate" from="0, 50, 25" to="360, 50, 25" dur="2s" begin="1s" repeatCount="indefinite" ></animateTransform> </rect> </svg> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <animateTransform attributeName="transform" type="rotate" values="0 50 25; -360 50 25" dur="2s" begin="1s" repeatCount="indefinite" ></animateTransform> </rect> </svg> -
缩放
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <animateTransform attributeName="transform" type="scale" from="1 1" to="2 3" dur="2s" begin="1s" repeatCount="indefinite" ></animateTransform> </rect> </svg> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <rect x="0" y="0" width="100" height="50" fill="red"> <animateTransform attributeName="transform" type="scale" values="1; 0.5" dur="2s" begin="1s" repeatCount="indefinite" ></animateTransform> </rect> </svg>
-
-
AnimateMotion
-
<animateMotion>定义了一个元素如何沿着运动路径进行移动- 动画元素的坐标原点,会影响元素运动路径,建议从(0, 0)开始
- 要复用现有路径,可在
<animateMotion>元素中使用<mpath>元素
-
<aniamteMotion>元素常用属性:-
path:定义运动的路径,值和
<path>元素的 d 属性一样,也可用 href 引用 一个<path>。 -
rotate :动画元素自动跟随路径旋转,使元素动画方向和路径方向相同,值类型:
<数字> | auto | auto-reverse; 默认值:0 -
动画值属性: from、to 、values
-
动画时间属性: begin、dur、fill、repeatCount
-
<!DOCTYPE html> <html lang="en"> <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"> <title>Document</title> <style> body { margin: 0; padding: 0; background-image: url(../images/grid.png); } svg { background-color: rgba(255, 0, 0, 0.1); } </style> </head> <body> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <!-- 一条路径 --> <path d="M 0 100, L 100 30, L 200 100, L 300 30" fill="transparent" stroke="red"></path> <!-- 一辆车 --> <rect x="-10" y="-5" width="20" height="10" rx="4" ry="4" fill="red"> <animateMotion path="M 0 100, L 100 30, L 200 100, L 300 30" rotate="auto" dur="4s" fill="freeze" repeatCount="indefinite" ></animateMotion> </rect> </svg> <svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" > <!-- 一条路径 --> <path id="linePath" d="M 0 100, L 100 30, L 200 100, L 300 30" fill="transparent" stroke="red"></path> <!-- 一辆车 --> <rect id="car" x="-10" y="-5" width="20" height="10" rx="4" ry="4" fill="red"></rect> <!-- 动画 --> <animateMotion href="#car" rotate="auto" dur="4s" fill="freeze" > <!-- 引用路径 --> <mpath href="#linePath"></mpath> </animateMotion> </svg> </body> </html> -
五、SVG + SMIL动画案例
5.1 飞机飞行轨迹
<svg width="400" height="200" viewBox="0 0 3387 1270" xmlns="http://www.w3.org/2000/svg">
<defs>
<style>
svg {
background-color: #28505d;
}
/**飞机飞行路线**/
.planePath {
stroke: #d9dada;
stroke-width: 0.5%;
stroke-dasharray: 1% 2%;
stroke-linecap: round;
fill: none;
}
/**飞机颜色**/
.fil1 {
fill: #d9dada;
}
.fil2 {
fill: #c5c6c6;
}
.fil4 {
fill: #9d9e9e;
}
.fil3 {
fill: #aeafb0;
}
</style>
</defs>
<!-- 飞行路径 -->
<path
id="planePath"
class="planePath"
d="M-226 626c439,4 636,-213 934,-225 755,-31 602,769 1334,658 562,-86 668,-698 266,-908 -401,-210 -893,189 -632,630 260,441 747,121 1051,91 360,-36 889,179 889,179"
/>
<!-- 飞机图形-->
<g id="plane">
<polygon
class="fil1"
points="-141,-10 199,0 -198,-72 -188,-61 -171,-57 -184,-57 "
/>
<polygon class="fil2" points="199,0 -141,-10 -163,63 -123,9 " />
<polygon
class="fil3"
points="-95,39 -113,32 -123,9 -163,63 -105,53 -108,45 -87,48 -90,45 -103,41 -94,41 "
/>
<path
class="fil4"
d="M-87 48l-21 -3 3 8 19 -4 -1 -1zm-26 -16l18 7 -2 -1 32 -7 -29 1 11 -4 -24 -1 -16 -18 10 23zm10 9l13 4 -4 -4 -9 0z"
/>
<polygon
class="fil1"
points="-83,28 -94,32 -65,31 -97,38 -86,49 -67,70 199,0 -123,9 -107,27 "
/>
</g>
<!-- 动画效果 -->
<animateMotion
href="#plane"
rotate="auto"
dur="5"
repeatCount="indefinite"
>
<mpath href="#planePath"></mpath>
</animateMotion>
</svg>
5.2 播放器
<svg
xmlns="http://www.w3.org/2000/svg"
width="80"
height="100"
viewBox="0 0 80 100"
style="background: #e74c3c;"
>
<!-- line 1 -->
<rect
fill="#fff"
width="3"
height="100"
transform="rotate(180,3,50)"
>
<animate
attributeName="height"
values="30; 100; 30"
dur="1s"
repeatCount="indefinite"
begin="0s"
>
</animate>
</rect>
<!-- line2 -->
<rect
x="17"
fill="#fff"
width="3"
height="100"
transform="rotate(180 20 50)"
>
<animate
attributeName="height"
values="30; 100; 30"
dur="1s"
repeatCount="indefinite"
begin="0.1s"
>
</animate>
</rect>
<!-- line3 -->
<rect
x="40"
fill="#fff"
width="3"
height="100"
transform="rotate(180,40,50)"
>
<animate
attributeName="height"
values="30; 100; 30"
dur="1s"
repeatCount="indefinite"
begin="0.3s"
>
</animate>
</rect>
<!-- line4 -->
<rect
x="60"
fill="#fff"
width="3"
height="100"
transform="rotate(180 58 50)"
>
<animate
attributeName="height"
values="30; 100; 30"
dur="1s"
repeatCount="indefinite"
begin="0.5s"
>
</animate>
</rect>
<!-- line4 -->
<rect
x="80"
fill="#fff"
width="3"
height="100"
transform="translate(0) rotate(180 76 50)"
>
<animate
attributeName="height"
values="30; 100; 30"
dur="1s"
repeatCount="indefinite"
begin="0.1s"
>
</animate>
</rect>
</svg>
5.3 加载动画
<svg
xmlns="http://www.w3.org/2000/svg"
width="100"
height="100"
viewBox="0 0 100 100"
style="background: #e74c3c;"
>
<circle fill="#fff" stroke="none" cx="6" cy="50" r="6">
<animate
attributeName="opacity"
values="0;1;0"
dur="1s"
begin="0s"
repeatCount="indefinite"
>
</animate>
</circle>
<circle fill="#fff" stroke="none" cx="26" cy="50" r="6">
<animate
attributeName="opacity"
values="0;1;0"
dur="1s"
begin="0.1s"
repeatCount="indefinite"
>
</animate>
</circle>
<circle fill="#fff" stroke="none" cx="46" cy="50" r="6">
<animate
attributeName="opacity"
values="0;1;0"
dur="1s"
begin="0.2s"
repeatCount="indefinite"
>
</animate>
</circle>
</svg>
5.4 转动动画
<svg
xmlns="http://www.w3.org/2000/svg"
width="100"
height="100"
viewBox="0 0 100 100"
>
<defs>
<style>
svg {
background-color: #e74c3c;
}
</style>
</defs>
<!-- big circle -->
<circle
fill="none"
stroke="#fff"
stroke-width="6"
stroke-miterlimit="15"
stroke-dasharray="14.2472,14.2472"
cx="50"
cy="50"
r="47"
>
<animateTransform
attributeName="transform"
type="rotate"
values="0 50 50;360 50 50"
dur="5s"
repeatCount="indefinite"
>
</animateTransform>
</circle>
<!-- small circle -->
<circle
fill="none"
stroke="#fff"
stroke-width="1"
stroke-miterlimit="10"
stroke-dasharray="10,10"
cx="50"
cy="50"
r="39"
>
<animateTransform
attributeName="transform"
type="rotate"
values="0 50 50;-360 50 50"
dur="5s"
repeatCount="indefinite"
>
</animateTransform>
</circle>
<!-- rect -->
<g fill="#fff">
<rect x="30" y="35" width="5" height="30">
<animateTransform
attributeName="transform"
type="translate"
values="0 -5; 0 5; 0 -5"
dur="1s"
begin="0s"
repeatCount="indefinite"
>
</animateTransform>
</rect>
<rect x="40" y="35" width="5" height="30">
<animateTransform
attributeName="transform"
type="translate"
values="0 -5; 0 5; 0 -5"
dur="1s"
begin="0.1s"
repeatCount="indefinite"
>
</animateTransform>
</rect>
<rect x="50" y="35" width="5" height="30">
<animateTransform
attributeName="transform"
type="translate"
values="0 -5; 0 5; 0 -5"
dur="1s"
begin="0.2s"
repeatCount="indefinite"
>
</animateTransform>
</rect>
<rect x="60" y="35" width="5" height="30">
<animateTransform
attributeName="transform"
type="translate"
values="0 -5; 0 5; 0 -5"
dur="1s"
begin="0.3s"
repeatCount="indefinite"
>
</animateTransform>
</rect>
<rect x="70" y="35" width="5" height="30">
<animateTransform
attributeName="transform"
type="translate"
values="0 -5; 0 5; 0 -5"
dur="1s"
begin="0.4s"
repeatCount="indefinite"
>
</animateTransform>
</rect>
</g>
</svg>
5.5 城市定位
<!DOCTYPE html>
<html lang="en">
<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" />
<title>Document</title>
<style>
.first-box {
width: 600px;
height: 314px;
background: url(./images/bg-location.png);
background-size: 100% 100%;
}
/* 定位的 icon */
#loc1 {
animation: moveLoc1Icon1 1s linear infinite alternate;
}
#loc2 {
animation: moveLoc1Icon2 1s linear infinite alternate;
animation-delay: 0.3s;
}
@keyframes moveLoc1Icon1 {
0%{
transform: translateY(-20px);
}
100%{
transform: translateY(0px);
}
}
@keyframes moveLoc1Icon2 {
0%{
transform: translateY(0px);
}
100%{
transform: translateY(10px);
}
}
#c1 {
animation: scaleEllipse1 2s linear infinite;
}
#c2 {
animation: scaleEllipse2 2s linear infinite;
animation-delay: 1s;
}
#c3, #c4 {
animation: scaleEllipse3 2s linear infinite;
}
#c4 {
animation-delay: 1s;
}
@keyframes scaleEllipse1 {
0%{
rx:0;
ry:0;
opacity: 1;
}
100% {
rx:16;
ry:8;
opacity: 0;
}
}
@keyframes scaleEllipse2 {
0%{
rx:0;
ry:0;
opacity: 1;
}
100%{
rx:12;
ry:6;
opacity: 0;
}
}
@keyframes scaleEllipse3 {
0%{
rx:0;
ry:0;
opacity: 1;
}
100%{
rx:10;
ry:5;
opacity: 0;
}
}
</style>
</head>
<body>
<div class="box-left first-box">
<svg
id="location"
height="400"
version="1.1"
width="744"
xmlns="http://www.w3.org/2000/svg"
>
<desc>Created with Snap</desc>
<defs>
<linearGradient
x1="100%"
y1="40.7087699%"
x2="4.9797314%"
y2="60.8683027%"
id="linearGradient-1"
>
<stop stop-color="#F5533D" stop-opacity="0" offset="0%"></stop>
<stop stop-color="#F5533D" offset="44.5180532%"></stop>
<stop stop-color="#F5533D" stop-opacity="0" offset="100%"></stop>
</linearGradient>
</defs>
<image
id="loc1"
xlink:href="./images/redPoint.png"
preserveAspectRatio="none"
x="265"
y="50.275"
width="55"
height="74"
></image>
<image
id="loc2"
xlink:href="./images/smPoint.png"
preserveAspectRatio="none"
x="155"
y="69.97776888888889"
width="25"
height="34"
></image>
<image
id="loc3"
xlink:href="./images/smPoint.png"
preserveAspectRatio="none"
x="435"
y="90.35983743115371"
width="25"
height="34"
></image>
<image
xlink:href=" ./images/bg-red.png"
preserveAspectRatio="none"
x="278"
y="94"
width="30"
height="100"
></image>
<image
xlink:href=" ./images/bg-red.png"
preserveAspectRatio="none"
x="160"
y="94"
width="15"
height="50"
></image>
<image
xlink:href="./images/first-smbg.png"
preserveAspectRatio="none"
x="438"
y="125"
width="20"
height="20"
></image>
<ellipse
id="c1"
cx="293"
cy="187"
rx="8.106666666666667"
ry="3.546666666666667"
fill="rgba(0,0,0,0)"
stroke="#ff0000"
style="opacity: 0.493333"
></ellipse>
<ellipse
id="c2"
cx="293"
cy="187"
rx="0"
ry="0"
fill="rgba(0,0,0,0)"
stroke="#ff0000"
style="opacity: 1"
></ellipse>
<ellipse
id="c3"
cx="168"
cy="143"
rx="0"
ry="0"
fill="rgba(0,0,0,0)"
stroke="#ff0000"
style="opacity: 1"
></ellipse>
<ellipse
id="c4"
cx="168"
cy="143"
rx="6.08"
ry="2.5333333333333337"
fill="rgba(0,0,0,0)"
stroke="#ff0000"
style="opacity: 0.493333"
></ellipse>
</svg>
</div>
</body>
</html>
5.6 水球动画
<!DOCTYPE html>
<html lang="en">
<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" />
<title>Document</title>
<style>
*,
*:before,
*:after {
box-sizing: border-box;
outline: none;
}
body {
background: #020438;
font: 14px/1 "Open Sans", helvetica, sans-serif;
}
.box {
height: 280px;
width: 280px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: #020438;
border-radius: 100%;
overflow: hidden;
}
.box .percent {
position: absolute;
left: 0;
top: 0;
z-index: 3;
width: 100%;
height: 100%;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
display: -webkit-flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 64px;
}
.box .water {
position: absolute;
left: 0;
top: 0;
z-index: 2;
width: 100%;
height: 100%;
transform: translate(0, 50%);
background: #4d6de3;
}
.box .water_wave {
width: 200%;
position: absolute;
bottom: 100%;
}
.box .water_wave_back {
right: 0;
fill: #c7eeff;
animation: wave-back 1.4s linear infinite;
}
.box .water_wave_front {
left: 0;
fill: #4d6de3;
margin-bottom: -1px;
animation: wave-front 0.7s linear infinite;
}
@keyframes wave-back {
0% {
transform: translateX(0);
}
100% {
transform: translateX(50%);
}
}
@keyframes wave-front {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-50%);
}
}
</style>
</head>
<body>
<div class="water-ball">
<svg
version="1.1"
xmlns="https://www.w3.org/2000/svg"
xmlns:xlink="https://www.w3.org/1999/xlink"
x="0px"
y="0px"
style="display: none"
>
<symbol id="wave">
<path
d="M420,20c21.5-0.4,38.8-2.5,51.1-4.5c13.4-2.2,26.5-5.2,27.3-5.4C514,6.5,518,4.7,528.5,2.7c7.1-1.3,17.9-2.8,31.5-2.7c0,0,0,0,0,0v20H420z"
></path>
<path
d="M420,20c-21.5-0.4-38.8-2.5-51.1-4.5c-13.4-2.2-26.5-5.2-27.3-5.4C326,6.5,322,4.7,311.5,2.7C304.3,1.4,293.6-0.1,280,0c0,0,0,0,0,0v20H420z"
></path>
<path
d="M140,20c21.5-0.4,38.8-2.5,51.1-4.5c13.4-2.2,26.5-5.2,27.3-5.4C234,6.5,238,4.7,248.5,2.7c7.1-1.3,17.9-2.8,31.5-2.7c0,0,0,0,0,0v20H140z"
></path>
<path
d="M140,20c-21.5-0.4-38.8-2.5-51.1-4.5c-13.4-2.2-26.5-5.2-27.3-5.4C46,6.5,42,4.7,31.5,2.7C24.3,1.4,13.6-0.1,0,0c0,0,0,0,0,0l0,20H140z"
></path>
</symbol>
</svg>
<div class="box">
<div class="percent">
<div class="percentNum" id="count">0</div>
<div class="percentB">%</div>
</div>
<div id="water" class="water">
<svg viewBox="0 0 560 20" class="water_wave water_wave_back">
<use xlink:href="#wave"></use>
</svg>
<svg viewBox="0 0 560 20" class="water_wave water_wave_front">
<use xlink:href="#wave"></use>
</svg>
</div>
</div>
</div>
<script>
window.onload = function() {
const waterEl = document.getElementById('water')
const countEl = document.getElementById('count')
let targetPercentage = 65
let currentPercentage = 0
let timeId = null
timeId = setInterval(() => {
currentPercentage ++
if(currentPercentage >= targetPercentage) {
clearInterval(timeId)
}
countEl.innerHTML = currentPercentage
// 防止溢出
if(currentPercentage <= 100) {
waterEl.style.transform = `translateY(${100 - currentPercentage}%)`
}
}, 60);
}
</script>
</body>
</html>