SVG属于矢量图形
- 扩展好:**矢量图像在测览器中放大缩小不会失真,**可被许多设备和浏览器中使用。而光栅图像(PNG、JPG)放大缩小会失真。
- 矢量图像是基于矢量的点、线、形状和数学公式来构建的图形,该图形是没有像素的,放大缩小是不会失真的。
- 光栅图像是由像素点构建的图像一一微小的彩色方块,大量像素点可以形成高清图像,比如照片。图像像素越多,质量越高.
- 灵活:SVG是W3C开发的标准,可结合其它的语言和技术一起使用,包括 CSS、Javacript HTML和 SMIL。SVG图像可以
直接使用JS和CSS进行操作,使用时非常方便和灵活,因为SVG也是可集成到 DOM 中的 - 可以动画:SVG 图像可以使用JS、CSS 和SMIL 进行动画处理。对于 Web 开发人员来说非常的友好
- 轻量级:与其它格式相比,SVG 图像的尺寸非常小。根据图像的不同,PNG 图像质量可能是 SVG 图像的50倍.
- 可打印:SVG图像可以以任何分辨率打印而不会损失图像质量。
- 利于SE)
- 优化:SVG图像可以不被搜索引擎索引,非常适合进行SEO优化
- 可压缩
- 易于编辑
SVG格式不适合做高清图片,不适合做像素级操作,SVG图像不应该做的很复杂,因为会影响加载速度,因为它是加载到DOM中的。
SVG和Canvas的区别
创建SVG
方式一
新建SVG文件,建议在首部编写XML文件声明,然后编写一个svg元素,并添加元素属性如:width,height,xmlns
,其中xmlns
是给svg元素绑定一个命名空间(http://www.w3.org/2000/svg),代表这个svg标签和它的子元素都属于该命名空间下。在svg元素中添加图形图形元素,在浏览器直接预览或嵌入到HTML中预览(嵌入HTML有六中方案)。
XML和DTD声明
vscode中安装对于的插件
创建一个1.svg文件编写如下代码
其中xml和DOCTYPE
部分都不是必填项,现代浏览器会自动添加。standalone
为no
时,就需要配合DOCTYPE
才有意义。下面书写的代码SVG部分就需要按照DOCTYPE
规定的语法进行书写。
xmlns
是开启域名空间,默认值如下,可以不写,浏览器会自动添加,当开启域名空间的时候,svg标签内部的所有代码都是在当前域名空间内部的,不会和外部冲突。version
是版本号。baseProfile
是渲染svg内容时候所需要的最小svg语言概述。full
代表最完整的svg语言概述,basic
代表基本的svg语言概述,tinuy
:只具备部分,属于轻量级的svg语言概述。
<!-- 通过文件后缀svg创建 -->
// SVG 1.0模版
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!-- 使用了no,代表要引入外部依赖声明 -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
baseProfile="full"
width="300"
height="150"
>
<rect x="10" y="10" width="100" height="50"></rect>
</svg>
// SVG 2.0
<?xml version="1.0" standalone="no" ?>
<svg
xmlns="http://www.w3.org/2000/svg"
width="300"
height="150"
>
<rect x="10" y="10" width="100" height="50"></rect>
</svg>
方式二
在HTML文件中使用svg如下,最后一个是直接采用简写,其中域名空间都是自动添加的。宽高都使用默认值。
<svg
xmlns="http://www.w3.org/2000/svg"
width="100"
height="100"
version="1.0"
baseProfile="full"
>
<rect x="0" y="0" width="100" height="100"></rect>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<rect x="0" y="0" width="100" height="100"></rect>
</svg>
<svg>
<rect x="0" y="0" width="100" height="100"></rect>
</svg>
方式三
使用JS脚本来创建SVG标签,创建的元素都是需要添加命名空间的。 创建的svg或rect元素都需要添加命名空间http://www.w3.org/2000/svg
。对于元素上的属性如果不带前缀的,则命名空间赋值为null。
如下xlink
属性就是需要添加的命名空间,代表href
属性后面跟的值需要符合该命名空间的规范。
在XML1.1命名空间规范中建议,不带前缀的属性命名空间的名称是没有值的,这个时候命名空间必须赋值为null
var xmlns = "http://www.w3.org/2000/svg";
const svg = document.createElementNS(xmlns, "svg");
const rect = document.createElementNS(xmlns, "rect");
svg.setAttributeNS(null, "width", "100");
svg.setAttributeNS(null, "height", "100");
rect.setAttributeNS(null, "width", 50);
rect.setAttributeNS(null, "height", 50);
svg.appendChild(rect);
document.body.appendChild(svg);
svg的使用方式
SVG中的网格坐标系
单位
视口
视口是SVG的可见区域,SVG画布的大小。可以将视口视为可看到的特定场景的窗口。使用svg元素的width和height
属性指定视口的大小。当设置了svg元素的宽高属性后,浏览器就会自动建立初始视口坐标系和初始用户坐标系
。 使用两个坐标系是因为SVG是矢量图,支持任意缩放,在用户坐标系中绘制的图形,最终都会参照视口坐标系来进行等比例缩放。
视口坐标系
视口坐标系是在视口上建立的坐标系,原点在视口的左上角0,0处。x轴向右,y轴向下。初始视口坐标系中的一个单位等于视口中的一个像素。
用户坐标系
用户坐标系也成为当前坐标系或正在使用的用户空间,后面所有的绘图都是参照该坐标系。 用户坐标系是建立在SVG视口上的坐标系。初始时,用户坐标系和视口坐标系都在同一个原点位置。一旦使用了viewBox
属性修改了初始用户坐标系,那么用户坐标系的作用范围就不再和视口坐标系相同
viewBox视图框
如下案例,下面代码中默认情况用户坐标和视口坐标是一样大小的,因此结果如图,但是给svg添加viewBox
属性修改用户坐标系后viewBox="0 0 100 100"
,结果如图
<svg width="300" height="300">
<circle cx="50" cy="50" r="50"></circle>
</svg>
这是因为修改了属性后,视口坐标系和用户坐标系的比例是相等的,而圆原本是绘制在用户坐标系的100,100以内,然后会按照比例进行缩放。于是原本的圆就会变大占满视口。
如下这段代码查看效果
<svg width="300" height="300" viewBox="50 50 100 100">
<circle cx="50" cy="50" r="50"></circle>
</svg>
用户坐标如图绿色区域,viewBox="50 50 100 100"
设置了用户坐标系中的可视区域范围,也就是蓝色区域如图,因此我们画的圆,只有四分之一是能看见的,最终缩放的时候,拿着四分之一的圆进行操作。
下面这段代码的效果如图,当比例不一样的时候最终缩放的结果会进行一个额外的垂直居中处理。 如果不想保持默认的垂直居中处理,则可以给svg元素添加preserveAspectRatios
属性设置none
强制用户坐标系拉伸填满整个视口坐标系或xMinYMin
图形在视口的最小x和y轴上显示。
<svg width="400" height="400" viewBox="0 0 200 100">
<circle cx="50" cy="50" r="50"></circle>
</svg>
红色小圆部分是一开始的情况,然后红色大圆是按照用户区域占满视口区域的情况,最终的绿色是进行居中处理的情况。
矩形的svg绘制方法如下
<svg width="400" height="400">
<rect x="0" y="0" width="100" height="20"></rect>
<rect x="150" y="200" width="100" height="50" rx="15" ry="15"></rect>
</svg>
圆的svg绘制方法如下
<svg width="400" height="400">
<circle cx="50" cy="50" r="10" fill="red"></circle>
</svg>
椭圆的svg绘制如下,rx
是横向半径,ry
是纵向半径
<svg width="400" height="400">
<ellipse cx="50" cy="50" rx="25" ry="50" fill="red"></ellipse>
</svg>
直线的svg绘制如下
<svg width="400" height="400">
// 起始坐标和结束坐标
<line x1="100" y1="100" x2="200" y2="100" stroke="red" stroke-width="5"></line>
</svg>
多条折线绘制
<svg width="400" height="400">
// 默认polyline 是不会闭合的,可以查看下面第一段代码,三个点之间并没有闭合
<!-- <polyline points="0 0,100 50 ,0 100" stroke="red" fill="transparent"></polyline> -->
<!-- <polyline points="0 0 100 50 0 100"></polyline> -->
<polyline points="0 ,0 ,100, 50, 0 ,100"></polyline>
</svg>
绘制多边形的svg如下
<svg width="400" height="400">
<polygon
points="10 10,100 50 ,0 100"
stroke="red"
fill="transparent"
></polygon>
</svg>
</body>
path路径绘制要求如下
<svg width="400" height="400">
<path
d="M 10 10 ,100 100 , 150 50"
fill="transparent"
stroke="red"
></path>
</svg>
路径中常用的参数如下
之前代码的基础上,给最后一个点添加命令参数Z
代表合并路径
<path
d="M 10 10 ,100 100 , 150 50 Z"
fill="transparent"
stroke="red"
></path>
需要注意大小写的命令参数具有不同意义,如下L和l
。l
代表相对路径,相对于前面的坐标点
svg中使用image元素,默认x,y坐标原点为0。如果width和height不设置,则默认为图片大小
<svg width="400" height="400">
<image href="./images/googlelogo_color_92x30dp.png"></image>
</svg>
svg绘制文字
元素组合g
如下这段代码中,就属于同一组,就可以使用一个g
标签包裹,两端代码功能一样,circle
标签会继承g
标签的样式属性
<svg width="400" height="400">
<circle cx="50" cy="50" r="25" fill="transparent" stroke="red"></circle>
<circle cx="70" cy="50" r="25" fill="transparent" stroke="red"></circle>
<circle cx="90" cy="50" r="25" fill="transparent" stroke="red"></circle>
</svg>
<g fill="transparent" stroke="red">
<circle cx="50" cy="50" r="25"></circle>
<circle cx="70" cy="50" r="25"></circle>
<circle cx="90" cy="50" r="25"></circle>
</g>
svg中图形元素的复用defs
使用defs
标签复用元素,凡是被复用的元素,默认是看不见的,需要配合use
元素使用。
对复用的元素进行引入use
<svg width="400" height="400">
<defs>
<!-- 给复用的元素打上唯一标识 -->
<rect id="rectangle" x="200" y="200" width="100" height="100"></rect>
<g fill="transparent" stroke="red">
<circle cx="50" cy="50" r="25"></circle>
<circle cx="70" cy="50" r="25"></circle>
<circle cx="90" cy="50" r="25"></circle>
</g>
</defs>
<!-- 指定复用的元素 x,y的坐标是相对于复用元素的坐标系进行平移操作即200,200-->
<use href="#rectangle" x="100" y="100"></use>
</svg>
元素复用symbol
// defs和symbol中复用的元素,可以在另一个svg中使用use元素使用
<svg width="400" height="400" display="none">
<symbol id="prev"><path d="M 80 0 , 20 50,80 100 Z"></path></symbol>
<symbol id="next">
<polygon points="120 0,180 50,120 100"></polygon>
</symbol>
</svg>
<svg width="400" height="400">
<use href="#prev" width="50" height="50"></use>
<use href="#next"></use>
</svg>
利用svg制作精灵图
在线合并精灵图网址:https://www.zhangxinxu.com/sp/svgo/
首先从阿里图标库中选取字体图标并下载为svg格式,然后进入该网页中选取进行合并。
合并完复制结果到代码中如下,发现都是使用symbol
标签进行复用
针对上面合并的代码进行如下使用
<svg width="20" height="20">
<use href="#yinle"></use>
</svg>
<svg width="50" height="50">
<use href="#yinle_1"></use>
</svg>
<svg width="100" height="150">
<use href="#yinletianchong"></use>
</svg>
描边属性stroke
使用CSS样式绘制图形
<svg width="300" height="300">
<rect width="100" height="100" x="100" y="100" style="fill: red"></rect>
</svg>
<svg width="300" height="300">
<defs>
<style>
.rect {
fill: red;
}
</style>
</defs>
<rect class="rect" width="100" height="100" x="100" y="100"></rect>
</svg>
渐变
offset
属性指定什么位置开始着色
<svg width="300" height="300">
<defs>
<linearGradient id="gradient">
<stop offset="0%" stop-color="red"></stop>
<stop offset="50%" stop-color="green"></stop>
<stop offset="100%" stop-color="blue"></stop>
</linearGradient>
</defs>
<rect class="rect" width="100" height="50" x="0" y="0" fill="url(#gradient)"></rect>
</svg>
其中x1="0" y1="0" x2="0" y2="1"
分别设置渐变的方向
svg实现毛玻璃效果
css中通过backdrop-filter
完成毛玻璃效果
<div class="box">
<img src="./images/avatar.jpeg" alt="" />
<div class="boli"></div>
</div>
.box {
width: 200px;
height: 200px;
position: relative;
}
.boli {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
/* 毛玻璃一下个 */
background-color: transparent;
backdrop-filter: blur(8px);
}
或者通过filter
css属性完成
<div class="box">
<img src="./images/avatar.jpeg" alt="" />
</div>
.box {
width: 200px;
height: 200px;
position: relative;
/* 将filter自带的模糊边界扩散溢出隐藏 */
overflow: hidden;
}
img {
filter: blur(8px);
}
使用svg制作模糊效果如下
<svg>
<defs>
<filter id="filter">
// stdDeviation设置模糊范围
<feGaussianBlur stdDeviation="8"></feGaussianBlur>
</filter>
</defs>
<image href="./images/avatar.jpeg" filter="url(#filter)"></image>
</svg>
transform形变
形变会修改坐标系,之后所有的操作都是基于新的坐标系完成的。
stroke描边动画
stroke-dasharray
代表一个虚线空格的大小。stroke-dashoffset="100"
代表元素偏移离开了容器中。通过设置动画效果,修该改值的大小。
<svg width="300" height="300">
<path
id="path"
d="M 100 100,L 200 100,L 200 140"
stroke="red"
fill="transparent"
stroke-width="10"
></path>
</svg>
#path {
/* 虚线距离,计算140是线条的长度占满 */
stroke-dasharray: 140;
/* 虚线偏移140,默认消失 */
stroke-dashoffset: 0;
animation: move 2s linear forwards;
}
@keyframes move {
from {
stroke-dashoffset: 140;
}
}
雪糕案例
<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>
然后svg的动画效果,都需要设置虚线的长度,而虚线的长度就是每一个路径的长度,这里使用js代码获取。getTotalLength
方法用于获取当前svg路径的长度。为了复用代码封装了一个函数getPathLength
window.onload = function () {
getPathLength("stick"); //252
getPathLength("drop"); //36
getPathLength("outline"); //1019
getPathLength("inside-l"); //486
getPathLength("inside-r"); //486
};
function getPathLength(className) {
let stickEl = document.getElementsByClassName(className)[0];
let stickLength = stickEl.getTotalLength();
console.log(className + "Length=", stickLength);
}
然后设置动画效果,这样子一个动画描边就出现了
.outline {
stroke-dasharray: 1020px;
stroke-dashoffset: 1020px;
animation: move 1s linear forwards;
}
.stick {
stroke-dasharray: 300px;
stroke-dashoffset: 300px;
animation: move 1s linear forwards;
}
.drop {
stroke-dasharray: 300px;
stroke-dashoffset: 300px;
animation: move 1s linear forwards;
}
.inside-l {
stroke-dasharray: 500px;
stroke-dashoffset: 500px;
animation: move 1s linear forwards;
}
.inside-r {
stroke-dasharray: 500px;
stroke-dashoffset: 500px;
animation: move 1s linear forwards;
}
@keyframes move {
to {
stroke-dashoffset: 0;
}
}
SMIL
SVG动画实现方法
优势
SVG支持SMIL动画元素:set,animate,animateColor,animateMotion四个元素
set元素
<svg width="300" height="300">
<rect x="0" y="0" width="100" height="20">
<set attributeName="x" to="200" begin="3"></set>
</rect>
<rect x="0" y="100" width="100" height="20" fill="red">
<set attributeName="x" to="200" begin="1"></set>
</rect>
</svg>
animate元素
<svg width="300" height="300">
<rect x="0" y="0" width="100" height="20">
<animate attributeName="x" to="200" dur="3" fill="freeze"></animate>
</rect>
<rect x="0" y="50" width="100" height="20">
<!-- from,to是只针对两个点进行操作,如果需要设置多个状态值,就需要使用values设置多个状态点信息,以分号隔离 -->
<animate attributeName="x" values="0;150;200" dur="3"></animate>
</rect>
</svg>
animateTransform
两者使用形变移动效果均一致,和给rect
元素直接添加transform
的区别在于使用animateTransform
元素会有一个过度效果
<svg width="300" height="300">
<rect x="0" y="0" width="100" height="20">
<animateTransform
attributeName="transform"
type="translate"
dur="3"
// 这里的from to values属性的值就是type字段对于的值
// y轴不变,x轴从0移动到200
from="0 0"
to="200 0"
></animateTransform>
</rect>
</svg>
<svg width="300" height="300">
<rect x="0" y="0" width="100" height="20">
<animateTransform
attributeName="transform"
type="translate"
dur="3"
values="0 0;200 0"
></animateTransform>
</rect>
</svg>
svg图形旋转,两者效果一致
<svg width="300" height="300">
<rect x="0" y="0" width="100" height="100">
<animateTransform
attributeName="transform"
type="rotate"
// 第一个参数为旋转弧度,后面两个参数设置旋转原点
from="0 50 50"
to="360 50 50"
dur="3"
></animateTransform>
</rect>
</svg>
<svg width="300" height="300">
<rect x="0" y="0" width="100" height="100">
<animateTransform
attributeName="transform"
type="rotate"
values="0 50 50;360 50 50"
dur="3"
></animateTransform>
</rect>
</svg>
使用svg中的缩放。
<svg width="300" height="300">
<rect x="0" y="0" width="100" height="100">
<animateTransform
attributeName="transform"
type="scale"
// x轴为缩放,y轴缩放一倍
from="1 1"
to="1 2"
dur="3"
></animateTransform>
</rect>
</svg>
<svg width="300" height="300">
<rect x="0" y="0" width="100" height="100">
<animateTransform
attributeName="transform"
type="scale"
values="1 1; 1 2"
dur="3"
></animateTransform>
</rect>
</svg>
animationMotion
<svg width="300" height="300">
<!-- 绘制线路,方便制作汽车路径 -->
<path
d="M 0 100,L 100 30,L 200 100,L 300 30"
fill="none"
stroke="red"
></path>
<!-- 模拟小汽车 -->
<rect x="0" y="0" width="20" height="10" fill="red" rx="5" ry="5"></rect>
</svg>
然后给汽车元素中添加animationMotion
元素,然后指定其运行路径path
就是刚才绘制的红色路径
<rect x="0" y="0" width="20" height="10" fill="red" rx="5" ry="5">
<animateMotion
path="M 0 100,L 100 30,L 200 100,L 300 30"
dur="2"
// 汽车运行轨迹随路径改变
rotate="auto"
></animateMotion>
</rect>
然后对上面的代码进行抽离复用处理
<svg width="300" height="300">
<!-- 绘制线路,方便制作汽车路径 -->
<path
id="linepath"
d="M 0 100,L 100 30,L 200 100,L 300 30"
fill="none"
stroke="red"
></path>
<!-- 模拟小汽车 -->
<rect x="-10" y="-5" width="20" height="10" fill="red" rx="5" ry="5">
<animateMotion dur="2" rotate="auto">
<!-- 复用路径 -->
<mpath href="#linepath"></mpath>
</animateMotion>
</rect>
</svg>
然后继续将animationMotion
抽离出来与rect
关联起来
<svg width="300" height="300">
<!-- 绘制线路,方便制作汽车路径 -->
<path
id="linepath"
d="M 0 100,L 100 30,L 200 100,L 300 30"
fill="none"
stroke="red"
></path>
<!-- 模拟小汽车 -->
<rect id="rectangle" x="-10" y="-5" width="20" height="10" fill="red" rx="5" ry="5"></rect>
<animateMotion href="#rectangle" dur="2" rotate="auto">
<!-- 复用路径 -->
<mpath href="#linepath"></mpath>
</animateMotion>
</svg>
飞机运行轨迹案例
假设如下案例,其中路径和飞机模型都已经绘制完成,现在只需要关联他们两个即可
只需要在svg中添加如下代码即可
// 关联运动物体
<animateMotion href="#plane" dur="3" rotate="auto">
// 关联路径
<mpath href="#planePath"></mpath>
</animateMotion>
水球波纹效果
基本图如下:大致思路是绘制了波纹效果,分别从左右两边开始运动(可以查看svg中的主体部分)。然后不断移动设置动画即可
</svg>
<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>
*,
*: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;
}
.box .water_wave_front {
left: 0;
fill: #4d6de3;
margin-bottom: -1px;
}
然后给front和back类添加过度动画效果
@keyframes moveback {
from {
transform: translateX(0);
}
to{
transform: translateX(50%);
}
}
@keyframes movefront{
from {
transform: translateX(0);
}
to{
transform: translateX(-50%);
}
}
应用动画后图形会产生波浪效果
然后编写js代码,其中water容器的位置会影响图中水波的位置,translateY
为0的时候水位到顶部,为100的时候没有水位
window.onload=()=>{
let count = document.querySelector('#count')
let water = document.querySelector('.water')
let currentCount=0
let timer=null
timer= setInterval(()=>{
currentCount++
if(currentCount>=100) {
clearInterval(timer)
return
}
count.innerHTML=currentCount
water.style.transform=`translateY(${100-currentCount}%)`
},60)
}
Snap.svg
除了使用原生的方法创建SVG,但是这种方法需要额外注意命名空间问题,很麻烦,因此还可以使用Snap库来快速创建。
这里采用引入安装包的方法使用,使用script标签引入该库,然后就可以使用Snap
方法创建一个画布
window.onload = () => {
// 创建svg,指定画布大小
let svg = Snap(300, 300);
// 坐标+半径
let c = svg.circle(100, 100, 50);
c.attr({
fill: "red",
});
// svg标签是存放在svg.node中
document.body.appendChild(svg.node);
};
除了可以创建一个svg,还可以选中一个已有的svg画布使用
<svg id="first" width="300" height="300">
<rect id="rect1" x="0" y="0" width="100" height="50"></rect>
</svg>
默认黑色
window.onload = () => {
let svg = Snap("#first");
// 选择一个已有的svg元素
let rect1 = svg.select("#rect1");
rect1.attr({
fill: "red",
});
};
如果想使用动画,基本代码如下,在上面代码的基础上创建一个圆
window.onload = () => {
let svg = Snap("#first");
// 选择一个已有的svg元素
let rect1 = svg.select("#rect1");
rect1.attr({
fill: "red",
});
let c = svg.circle(100, 100, 50);
Snap.animate(
100, //from
200, // to
function (val) {
// val就是from和to区间的值
c.attr({
cy: val,
});
},
1000,
mina.linear
);
};
额外写法
Snap.animate(
[100, 100], //from
[200, 200], // to
function (val) {
// val就是from和to区间的值
// 如果from和to是数组,那么val也是一个数组
c.attr({
cx: val[0],
cy: val[1],
});
},
1000,
mina.linear
);
大屏适配解决方案
大屏开发的注意事项
- 动画卡顿优化
- 然后动画很多造成页面卡顿,那就每一个动画都创建对应的渲染层,创建渲染层的好处是:重流和重绘只会针对当前的渲染层,而非整个界面。启用GPU加速,善用CSS3形变动画。
position:absolute和float
都会让某一个元素脱离文档流,让其重排和重绘只针对当前元素。 - 少用渐变和高斯模糊,对于性能不好的设备会造成卡顿,当不需要动画的时候,及时关闭动画
- 然后动画很多造成页面卡顿,那就每一个动画都创建对应的渲染层,创建渲染层的好处是:重流和重绘只会针对当前的渲染层,而非整个界面。启用GPU加速,善用CSS3形变动画。
- 字体大小设置问题
- 当使用rem或vw单位的时候,在JS中的样式单位就需要手动处理。
- 很多第三方库的字体默认都是px单位,因此第三方库的样式也需要手动处理
- 当大屏比例更大的时候,字体需要相应的调整字号
- 图片模糊问题
- 切图时切一倍图,二倍图,大屏用大图,小屏用小图。针对不同用户的屏幕大小使用不同的图片
- 建议使用svg矢量图,放大缩小不失真
- Echarts渲染引擎尽量选择SVG渲染引擎,SVG的扩展性更好,如果实在不行选择Canvas引擎