一、前言
公司或者个人logo如何描边呢?我因为这个好奇地去调查了一番,发现了svg用几行代码就能搞定,于是我写下这篇文章,希望能快速帮助大家理解实现描边动画
二、api
我们先来说一下本篇文章会用到的api
-
stroke-dasharray:控制用来描边的点划线的图案范式。
这里可以传入以空格代表分隔的数组:可以传入
任意数量的数字
,代表了分割的规律
。比如:- '1 ' : dash和间隔大小都为1
- '1 2':dash大小为1 ,间隔大小为2
- '1 2 3':dash大小为1,间隔大小为2,然后dash大小为3,间隔大小为1...不断循环下去
例子来自MDN:
<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg"> <!-- No dashes nor gaps 没设置stroke-dasharray--> <line x1="0" y1="1" x2="30" y2="1" stroke="black" /> <!-- Dashes and gaps of the same size stroke-dasharray只设置1个 --> <line x1="0" y1="3" x2="30" y2="3" stroke="black" stroke-dasharray="4" /> <!-- Dashes and gaps of different sizes stroke-dasharray设置2个--> <line x1="0" y1="5" x2="30" y2="5" stroke="black" stroke-dasharray="4 1" /> <!-- Dashes and gaps of various sizes with an odd number of values stroke-dasharray设置3个--> <line x1="0" y1="7" x2="30" y2="7" stroke="black" stroke-dasharray="4 1 2" /> <!-- Dashes and gaps of various sizes with an even number of values stroke-dasharray设置4个--> <line x1="0" y1="9" x2="30" y2="9" stroke="black" stroke-dasharray="4 1 2 3" /> </svg>
-
stroke-dashoffset:用于指定 stroke-dasharray
开始的偏移量
,这也是动画的原理的关键
。我画个图帮助理解:
通过控制stroke-dashoffset 可以使得原本的图形发生偏移,让用户只能看到在框框中的图形。这时候再配合上css3的animation,设置偏移动画的时间和效果,就可以实现描边动画的效果
-
styleSheets:可以获取网页上引入的link样式表和style样式表。
如果我们想要
动态设置@keyframe
,可以采用styleSheets的insertRule
方法:-
insertRule作用是来给当前样式表插入
新的样式规则
-
insertRule(rule, index) 中第一个参数是
必需
的,代表要插入的新规则 -
而index:可选,新规则插入的位置,样式表
起始位置
-
三、描边动画实现
先举个简单的例子,如下图:
步骤:
- 我们先找设计师或者各大网站(比如这个例子我就是去iconfont里搜索的)拿到svg标签。
<svg
t="1610851432472"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="7792"
width="200"
height="200"
>
<path
class="icon-path"
stroke="#000"
d="M177.152 655.36v-24.576c58.368 0 88.064-25.6 88.064-75.776V177.152c0-20.48-13.312-30.72-39.936-30.72-35.84 0-65.536 11.264-88.064 34.816C114.688 204.8 97.28 240.64 87.04 286.72L61.44 280.576l22.528-174.08c12.288 2.048 24.576 3.072 35.84 4.096 11.264 1.024 21.504 2.048 32.768 2.048h315.392c11.264 0 23.552-1.024 34.816-2.048 12.288-1.024 24.576-2.048 36.864-4.096v171.008l-22.528 3.072c-6.144-87.04-50.176-131.072-130.048-131.072-27.648 0-40.96 9.216-40.96 27.648v377.856c0 50.176 29.696 75.776 88.064 75.776V655.36H177.152z"
fill="#90C9C4"
p-id="7793"
></path>
<path
class="icon-path"
stroke="#000"
d="M600.064 917.504v-24.576c58.368 0 88.064-25.6 88.064-75.776V440.32c0-20.48-13.312-30.72-39.936-30.72-35.84 0-65.536 11.264-88.064 34.816-22.528 23.552-38.912 58.368-50.176 105.472l-25.6-6.144 22.528-174.08c12.288 2.048 24.576 3.072 35.84 4.096 11.264 1.024 21.504 2.048 32.768 2.048H890.88c11.264 0 23.552-1.024 34.816-2.048 12.288-1.024 24.576-2.048 36.864-4.096v171.008l-22.528 3.072c-6.144-87.04-50.176-131.072-130.048-131.072-27.648 0-40.96 9.216-40.96 27.648v377.856c0 50.176 29.696 75.776 88.064 75.776v24.576H600.064z"
fill="#4FA39A"
p-id="7794"
></path>
</svg>
-
一般拿到svg的图片可能大小不合适,可以为它设置宽高
-
接着要设置stroke-dasharray的大小。
重点
:- svg元素上有一个方法
getTotalLength
方法去获取到当前path的长度,是给stroke-dasharray赋值 - 如果这时候有多个path元素,就去它们分别计算取
最大值
。 - 这里通过getTotalLength去取值,并且取最大值的原因是:
- 如果随便设置一个很大值,这时候如果业务场景需要不断地重复进行描边动画,这时候因为stroke-dasharray设置过大,会
导致动画停留过久
- 而设置过小则因为stroke-dasharray方法是对图形切割的,会导致图形出现
断层
- 如果随便设置一个很大值,这时候如果业务场景需要不断地重复进行描边动画,这时候因为stroke-dasharray设置过大,会
<script> document.addEventListener("DOMContentLoaded", () => { const logo = document.getElementsByClassName("icon-path")[0]; console.log(logo.getTotalLength()); }); </script>
- svg元素上有一个方法
-
接着就是写css动画了
<style> .icon { width: 300px; height: 300px; } .icon-path { fill: none; animation: animation 5s linear forwards; } @keyframes animation { 0% { fill: white; stroke: #333; stroke-dasharray: 2718; stroke-dashoffset: 2718; } 50% { fill: white; stroke: #333; stroke-dasharray: 2718; stroke-dashoffset: 0; } 75% { fill: #e5e7e7; stroke: white; } 100% { fill: #90c9c4; stroke: white; } } </style>
分析:
- animation 是实现动画的关键,我们来介绍其中的几个比较容易忽略的属性
linear
这代表动画效果,可以参考animation-timing-functionforwards
代表最后一帧是保持住当前图形而不用回到初始的时候。可以参考animation-fill-mode- 这里animation 还可以设置数字或者infinite 代表重复次数或者无穷次,不设置则不重复,可以参考animation-iteration-count
- 2718是我经过getTotalLength去计算出的最大值。
- 0% 到 50% 是实现图形从无到有的形成过程,
stroke-dashoffset设置为0代表展示图形
- 75%到100%的过程代表为图形上色的过程,这里的fill代表填充的颜色,这一般在拿到svg元素的就已经写在svg标签里了
- animation 是实现动画的关键,我们来介绍其中的几个比较容易忽略的属性
-
到此整个流程结束,我们用一张图来总结吧:
四、进阶 | 通用设置
通过上一章节我们已经知道了整个svg实现描边动画的步骤了,但是有一个新的问题产生了:如果我们svg图形色彩比较丰富,比较复杂了。我们还是手动一个一个为每个svg中的path元素去计算path长度,然后找到最大值吗?手动为每个path添加animation吗?这显然很不通用,也不是我们程序员该做的事。所以本篇将讲解更通用的设置:
改善想法
:
- 当我们svg图形比较复杂的时候由多个path组合而成,我们需要计算所有path的路径的长度,所以我们需要通过
循环获取path元素得到全部路径长度
,取其中的最大值。
具体代码如下:
let pathElements = document.getElementsByTagName("path");
let maxPath = 0;
for (let i = 0; i < pathElements.length; i++) {
const pathElement = pathElements[i];
maxPath =
maxPath < pathElement.getTotalLength()
? pathElement.getTotalLength()
: maxPath;
}
- 而要为每个path动态设置animation的关键在于如何
动态设置@keyframes
,这里就要用到styleSheets
中的insertRule
(相关概念已经在api
中讲解)
for (let j = 0; j < pathElements.length; j++) {
const pathElement = pathElements[j];
const fill = pathElement.getAttribute("fill");
const path = {
fill: "none",
animation: `animation${j} 5s linear 3 forwards`,
};
setStyle(pathElement, path);
document.styleSheets[0].insertRule(
`
@keyframes animation${j} {
0% {
fill: white;
stroke: #333;
stroke-dasharray: ${maxPath};
stroke-dashoffset: ${maxPath};
}
50% {
fill: white;
stroke: #333;
stroke-dasharray: ${maxPath};
stroke-dashoffset: 0;
}
100% {
fill: ${fill};
stroke: ${fill};
}
}
`
);
}
分析:
- 这里面的内容可以做成很通用,比如传入动画时间等等,这里提供一个思路,就没写得很具体了
最后整体代码如下:
<!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>
</style>
<svg
t="1610851432472"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="7792"
width="200"
height="200"
>
<path
class="icon-path"
stroke="#000"
d="M177.152 655.36v-24.576c58.368 0 88.064-25.6 88.064-75.776V177.152c0-20.48-13.312-30.72-39.936-30.72-35.84 0-65.536 11.264-88.064 34.816C114.688 204.8 97.28 240.64 87.04 286.72L61.44 280.576l22.528-174.08c12.288 2.048 24.576 3.072 35.84 4.096 11.264 1.024 21.504 2.048 32.768 2.048h315.392c11.264 0 23.552-1.024 34.816-2.048 12.288-1.024 24.576-2.048 36.864-4.096v171.008l-22.528 3.072c-6.144-87.04-50.176-131.072-130.048-131.072-27.648 0-40.96 9.216-40.96 27.648v377.856c0 50.176 29.696 75.776 88.064 75.776V655.36H177.152z"
fill="#90C9C4"
p-id="7793"
></path>
<path
class="icon-path"
stroke="#000"
d="M600.064 917.504v-24.576c58.368 0 88.064-25.6 88.064-75.776V440.32c0-20.48-13.312-30.72-39.936-30.72-35.84 0-65.536 11.264-88.064 34.816-22.528 23.552-38.912 58.368-50.176 105.472l-25.6-6.144 22.528-174.08c12.288 2.048 24.576 3.072 35.84 4.096 11.264 1.024 21.504 2.048 32.768 2.048H890.88c11.264 0 23.552-1.024 34.816-2.048 12.288-1.024 24.576-2.048 36.864-4.096v171.008l-22.528 3.072c-6.144-87.04-50.176-131.072-130.048-131.072-27.648 0-40.96 9.216-40.96 27.648v377.856c0 50.176 29.696 75.776 88.064 75.776v24.576H600.064z"
fill="#4FA39A"
p-id="7794"
></path>
</svg>
</head>
<body>
<script>
function setStyle(target, styles) {
for (const k in styles) {
target.style[k] = styles[k];
}
}
document.addEventListener("DOMContentLoaded", () => {
let pathElements = document.getElementsByTagName("path");
let maxPath = 0;
for (let i = 0; i < pathElements.length; i++) {
const pathElement = pathElements[i];
maxPath =
maxPath < pathElement.getTotalLength()
? pathElement.getTotalLength()
: maxPath;
}
for (let j = 0; j < pathElements.length; j++) {
const pathElement = pathElements[j];
const fill = pathElement.getAttribute("fill");
const path = {
fill: "none",
animation: `animation${j} 5s linear 3 forwards`,
};
setStyle(pathElement, path);
document.styleSheets[0].insertRule(
`
@keyframes animation${j} {
0% {
fill: white;
stroke: #333;
stroke-dasharray: ${maxPath};
stroke-dashoffset: ${maxPath};
}
50% {
fill: white;
stroke: #333;
stroke-dasharray: ${maxPath};
stroke-dashoffset: 0;
}
100% {
fill: ${fill};
stroke: ${fill};
}
}
`
);
}
});
</script>
</body>
</html>
五、更多效果展示
我们之后想要换其他svg图形,就只要去替换html中的svg元素就可以了(记得设置宽高)。
但是不足
的地方是如果一些svg过于复杂
,可能形成的效果会不尽人意了。(太复杂的动画建议还是让ui生成gif动图,也节省空间)
下面展示的svg都是去iconfont的插件库找的
(1) 跑车
(2) 404
(3) 福
(4)呐喊
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!