成果展示

最终结果
上面这个动画就是一个简单的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
    <!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>
  2. 接着添加 stroke-dasharraystroke-width样式,使得直线变粗以及有间隙

    1
    2
    3
    4
    5
    6
    7
    .p {
    stroke: black;
    /* 描边的宽度 */
    stroke-width: 10;
    /* 虚线间隔 */
    stroke-dasharray: 10;
    }

    虚线

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

  4. 有了上面这两个样式,就可以通过一个动画来实现线段的描边了。

    • 先将虚线间隔调整为线段长度
      1
      stroke-dasharray: 10;
    • 将整条线左移整个宽
      1
      stroke-dashoffset: 50;
    • 添加一个动画并应用
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      .p {
      stroke: black;
      /* 描边的宽度 */
      stroke-width: 10;
      /* 虚线间隔 */
      stroke-dasharray: 50;
      stroke-dashoffset: 50;
      animation: stroke 2s forwards;
      }

      @keyframes stroke {
      to {
      stroke-dashoffset: 0;
      }
      }
      就可以得到这样子的动画
      直线动画
以为这样子就结束了?no~ no~ no~😉
  1. 由于上面的虚线长度和偏移量都是固定的,当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>
  2. 最后将<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
<!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>