成果展示

最终结果
上面这个动画就是一个简单的svg描边动画的实现,下面来看看如何一步一步得到吧,

步骤

  1. 先用 svg 画出一条直线。
    直线
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<!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>
.p {
stroke: black;
}
</style>
</head>

<body>
<svg
class="icon"
width="50"
,height="50">
<line
class="p"
x1="0%"
y1="50%"
x2="100%"
y2="50%" />
<!-- <circle class='p' cx="50%" cy="50%" r="30%" /> -->
</svg>
</body>
</html>
  1. 接着添加 stroke-dasharraystroke-width样式,使得直线变粗以及有间隙
1
2
3
4
5
6
7
.p {
stroke: black;
/* 描边的宽度 */
stroke-width: 10;
/* 虚线间隔 */
stroke-dasharray: 10;
}

虚线

  1. 再添加一个stroke-dashoffset:偏移量,左正右负。
    偏移

  2. 有了上面这两个样式,就可以通过一个动画来实现线段的描边了。 - 先将虚线间隔调整为线段长度
    css stroke-dasharray: 10; - 将整条线左移整个宽
    css stroke-dashoffset: 50; - 添加一个动画并应用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    .p {
    stroke: black;
    /_ 描边的宽度 _/
    stroke-width: 10;
    /_ 虚线间隔 _/
    stroke-dasharray: 50;
    stroke-dashoffset: 50;
    animation: stroke 2s forwards;
    }

    @keyframes stroke {
    to {
    stroke-dashoffset: 0;
    }
    }
    ```
    就可以得到这样子的动画
    ![直线动画](https://oss.snailuu.cn/article/center/2023070905.gif)

    <center><big>以为这样子就结束了?no~ no~ no~😉</big></center>

  3. 由于上面的虚线长度和偏移量都是固定的,当svg图标长度发生变化时就不能自适应了,因此需要改成一个变量,这里采用js实现。

    • 先将长度都用变量表示
      1
      2
      3
      4
      5
      6
      7
      8
      9
      .p {
      stroke: black;
      /* 描边的宽度 */
      stroke-width: 10;
      /* 虚线间隔 */
      stroke-dasharray: var(--l);
      stroke-dashoffset: var(--l);
      animation: stroke 2s forwards;
      }
    • 加入js代码
      1
      2
      3
      4
      5
      6
      7
      8
      <script>
      const paths = document.querySelectorAll(".icon .p");
      paths.forEach(path => {
      const len = path.getTotalLength();
      path.style.setProperty('--l', len + 1);
      /*+1的目的是弥补精度*/
      })
      </script>
  4. 最后将<line/> 换成其它的svg代码

1
<svg t="1688872979658" class="icon" viewBox="0 0 1213 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1041" width="200" height="200"><path d="M1024 0c104.561778 0 189.62963 85.067852 189.62963 189.62963v644.74074c0 104.561778-85.067852 189.62963-189.62963 189.62963H900.740741a47.407407 47.407407 0 1 1 0-94.814815h123.259259c52.280889 0 94.814815-42.533926 94.814815-94.814815V189.62963c0-52.280889-42.533926-94.814815-94.814815-94.814815H189.62963c-52.280889 0-94.814815 42.533926-94.814815 94.814815v130.37037a47.407407 47.407407 0 1 1-94.814815 0V189.62963C0 85.067852 85.067852 0 189.62963 0zM878.231704 213.333333c67.309037 0 122.064593 54.755556 122.064592 122.064593V497.777778a47.407407 47.407407 0 1 1-94.814815 0V375.61837L766.160593 516.683852A188.397037 188.397037 0 0 1 791.703704 611.555556V834.37037c0 104.561778-85.067852 189.62963-189.62963 189.62963H189.62963C85.067852 1024 0 938.932148 0 834.37037V611.555556c0-104.561778 85.067852-189.62963 189.62963-189.62963h412.444444c35.678815 0 69.082074 9.91763 97.611852 27.117037L838.84563 308.148148H715.851852a47.407407 47.407407 0 1 1 0-94.814815zM602.074074 516.740741H189.62963c-52.280889 0-94.814815 42.533926-94.814815 94.814815V834.37037c0 52.280889 42.533926 94.814815 94.814815 94.814815h412.444444c52.280889 0 94.814815-42.533926 94.814815-94.814815V611.555556c0-52.280889-42.533926-94.814815-94.814815-94.814815z" p-id="1042"></path></svg>

svg标签的类增加一个icon,在path标签中增加一个p类,对于p类的样式增加一个fill:none的样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.p {
fill: none;
stroke: black;
/* 描边的宽度 */
stroke-width: 10;
/* 虚线间隔 */
stroke-dasharray: var(--l);
stroke-dashoffset: var(--l);
animation: stroke 2s forwards;
}

@keyframes stroke {
to {
stroke-dashoffset: 0;
fill: black;
}
}

最终代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!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>
.p {
fill: none;
stroke: black;
/* 描边的宽度 */
stroke-width: 10;
/* 虚线间隔 */
stroke-dasharray: var(--l);
stroke-dashoffset: var(--l);
animation: stroke 2s forwards;
}

@keyframes stroke {
to {
stroke-dashoffset: 0;
fill: black;
}
}
</style>
</head>

<body>
<svg
t="1688872979658"
class="icon"
viewBox="0 0 1213 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1041"
width="50"
height="50">
<path
class="p"
d="M1024 0c104.561778 0 189.62963 85.067852 189.62963 189.62963v644.74074c0 104.561778-85.067852 189.62963-189.62963 189.62963H900.740741a47.407407 47.407407 0 1 1 0-94.814815h123.259259c52.280889 0 94.814815-42.533926 94.814815-94.814815V189.62963c0-52.280889-42.533926-94.814815-94.814815-94.814815H189.62963c-52.280889 0-94.814815 42.533926-94.814815 94.814815v130.37037a47.407407 47.407407 0 1 1-94.814815 0V189.62963C0 85.067852 85.067852 0 189.62963 0zM878.231704 213.333333c67.309037 0 122.064593 54.755556 122.064592 122.064593V497.777778a47.407407 47.407407 0 1 1-94.814815 0V375.61837L766.160593 516.683852A188.397037 188.397037 0 0 1 791.703704 611.555556V834.37037c0 104.561778-85.067852 189.62963-189.62963 189.62963H189.62963C85.067852 1024 0 938.932148 0 834.37037V611.555556c0-104.561778 85.067852-189.62963 189.62963-189.62963h412.444444c35.678815 0 69.082074 9.91763 97.611852 27.117037L838.84563 308.148148H715.851852a47.407407 47.407407 0 1 1 0-94.814815zM602.074074 516.740741H189.62963c-52.280889 0-94.814815 42.533926-94.814815 94.814815V834.37037c0 52.280889 42.533926 94.814815 94.814815 94.814815h412.444444c52.280889 0 94.814815-42.533926 94.814815-94.814815V611.555556c0-52.280889-42.533926-94.814815-94.814815-94.814815z"
p-id="1042"></path>
</svg>
<script>
const paths = document.querySelectorAll('.icon .p');
paths.forEach((path) => {
const len = path.getTotalLength();
path.style.setProperty('--l', len);
});
</script>
</body>
</html>