用 SVG 描边动画送一份平安夜祝福

开发 前端
SVG 是网页里画矢量图的技术,可以用 rect、circle、line 等画一些具体的图形,也可以用 path 来画更复杂的图形。

[[441892]]

今晚是平安夜,提前给大家送份祝福。

SVG 是用 Illustrator 画的,苹果是手绘的(虽然是画的丑了点 0.0)。

按照惯例,看完效果之后我们来学习下它的实现原理。

思路分析

SVG 是网页上画矢量图的技术,有 line(线)、polyline(折线)、polygon(多边形)、react(矩形)、circle(圆形)、ellipsis(椭圆)等图形,也可以通过 path 来描述任意的形状。

  1. <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"
  2.  
  3.     <rect width="300" height="100"/> 
  4.     <path d="M250 150 L150 350 L350 350 Z" /> 
  5.  
  6. </svg> 

其中 M 是 moveTo,移动到某个位置开始画,L 是 lineTo,画一条直线,Z 是 closePath,完成绘制。当然,还可以绘制曲线等,api 和 canvas 里画图形的 api 差不多。

那我们需要用代码手画苹果和文字的 path 么?

不用,可以用 Illastrator 这种矢量绘图软件,它有钢笔、文字等各种绘图工具,用这些工具绘制完然后导出 SVG 就行。

SVG 可以设置两个方面的属性,一个是线条相关的,主要是 stroke,一个是填充相关的,主要是 fill。

stroke 相关的样式有 stroke-dasharray 来指定用虚线画。

比如 stroke-dasharray:10 20; 是虚线长度 10px,间隔 20px。

也可以用 stroke-dasharray 指定虚线的 offset,也就是偏移位置,往左偏移是正,往右是负。

比如 stroke-dashoffset: 1 就是往左偏移 1px。

注意这个 stroke-dashoffset,我们往左偏移全部的长度,然后再慢慢移动回原来位置,也就是 offset 由正数到 0,不就是描边的效果的呢?

这就是 SVG 描边动画的原理。

知道了这种动画要改变什么属性,那我们要用定时器自己去改变么?不用,可以用一些动画框架来修改属性值,比如 anime.js,它还支持设置时间函数,比如匀速、加速等。

理清了大概的原理,那我们来动手实现下吧。

代码实现

首先先把 SVG 准备好,我们用 Illastrator 来画:

使用文字工具写祝福的文字,然后选择“创建轮廓”,就会变成一个轮廓数据,然后选择导出 SVG 就行了。

苹果可以用钢笔手画,画完后点击“创建复合路径”,变成 path 的形式,然后导出 SVG:

画好了 SVG 之后,我们再实现动画效果:

  • 最开始把 stroke-dashoffset 设置为 SVG 的长度,然后用动画的方式慢慢变为 0。
  • 每一个 path 画完之后就用 fill 属性来填充颜色。

我们给每个 path 加上一个 class,然后来做动画。

使用 anime.js 来改变 stroke-dashoffset 实现描边的动画效果。

需要传入这些参数:

  • 指定 targets,也就是添加动画效果的元素
  • 指定 strokeDashOffset 属性值从 SVG 的长度慢慢变到 0。
  • 指定 easing 时间函数,linear 是匀速
  • 指定 duration 时间间隔
  • 指定每个元素的执行动画的 delay 时间
  • 还可以指定每个元素动画结束之后修改一些属性值
  1. const duration = 800; 
  2.  
  3. anime({ 
  4.     targets: ".svg-path"
  5.     strokeDashoffset: function(item) {  
  6.         const svgLength = anime.setDashoffset(item);  
  7.         return [svgLength, 0];  
  8.     }, 
  9.     easing: "linear"
  10.     duration, 
  11.     delay: function (item, index) { 
  12.         return duration * index
  13.     }, 
  14.     updatefunction (anim) { 
  15.         const color = ['red''pink''purple','skyblue''blue','red''green','green']; 
  16.         for(let i = 1; i <= color.length; i++) { 
  17.             if (anim.currentTime >= duration * i) { 
  18.                 document.querySelector(".path" + i).style.fill = color[i-1]; 
  19.             } 
  20.         } 
  21.     }, 
  22.     autoplay: true 
  23. }); 

我们给每个元素设置了不同的动画 delay 时间,就是一个个做动画的效果。

每个元素执行结束之后,判断了下时间,如果是已经执行完动画的元素,就 fill 上颜色。

stokeDashOffset 的初始值是 SVG 的长度(向左偏移),然后慢慢变为 0(回到原点)。

这样,我们就实现了想要的描边动画的效果。

全部代码:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3.  
  4. <head> 
  5.     <meta charset="UTF-8"
  6.     <meta http-equiv="X-UA-Compatible" content="IE=edge"
  7.     <meta name="viewport" content="width=device-width, initial-scale=1.0"
  8.     <title>平安夜快乐</title> 
  9.     <script src="https://unpkg.com/animejs@3.2.1/lib/anime.min.js"></script> 
  10.     <style> 
  11.         body { 
  12.             background-color: #000; 
  13.         } 
  14.  
  15.         .box { 
  16.             width: 600px; 
  17.             height: 300px; 
  18.             text-align: center; 
  19.             margin: 0 auto; 
  20.         } 
  21.  
  22.         svg { 
  23.             width: 600px; 
  24.             height: 300px; 
  25.             padding-top: 30px; 
  26.         } 
  27.         .svg-path { 
  28.             fill: #000; 
  29.             stroke: #fff; 
  30.         } 
  31.     </style> 
  32. </head> 
  33.  
  34. <body> 
  35.     <div class="box"
  36.         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50.34 333.9"
  37.             <path class="svg-path path1" 
  38.                 d="M289.75,295.3v1.8a8.37,8.37,0,0,1-.24,2.1c-16.68,0-29.94-.36-39.78-1.2a7.41,7.41,0,0,1-.17-2,6.49,6.49,0,0,1,.29-2Q269.92,293.92,289.75,295.3Zm-29.58,22.92a9.45,9.45,0,0,1-3.54,2.22,50.86,50.86,0,0,1-5.82-8.58,9.62,9.62,0,0,1,3.61-2.16A98.3,98.3,0,0,1,260.17,318.22Zm26.76,8.7a6.52,6.52,0,0,1,.18,1.86,6,6,0,0,1-.18,1.86c-.6.24-3.78.36-9.48.36h-4.86c-.12,2.76-.3,5.22-.48,7.5a6.22,6.22,0,0,1-2,.24,4.7,4.7,0,0,1-1.68-.24c-.18-2.4-.3-4.86-.36-7.5-9.54,0-14.88-.12-15.95-.36a5.88,5.88,0,0,1-.25-2,5.49,5.49,0,0,1,.3-2c4.92-.12,10.2-.18,15.78-.18v-3.42q0-5.85.36-12.24a10.57,10.57,0,0,1,2-.24,9.05,9.05,0,0,1,2,.24q.36,6.48.36,11.88v3.72h4.74A79,79,0,0,1,286.93,326.92Zm5-15.12a49.35,49.35,0,0,1-6.66,9.54,4.71,4.71,0,0,1-3.06-1.8,46.39,46.39,0,0,1,6.18-9.84A6.85,6.85,0,0,1,291.91,311.8Z" 
  39.                 transform="translate(-245.6 -293.92)" /> 
  40.             <path class="svg-path path2" 
  41.                 d="M254.11,372.4a129.35,129.35,0,0,1-.71,13,6.56,6.56,0,0,1-2.11.24,2.82,2.82,0,0,1-2-.48,88.15,88.15,0,0,1,.67-13,20.77,20.77,0,0,1,2.1-.12A5.79,5.79,0,0,1,254.11,372.4Zm34.68,16.86v2c-7.2.6-14.34,1-21.54,1.32-.9,2.52-1.74,5.1-2.58,7.62,4.08,1,8.16,1.8,12.3,2.64,1-2.52,1.92-4.92,2.88-7.08q1.8.54,3.78,1.26c-.66,2.28-1.38,4.56-2.22,6.72l5.46,1.08a16.5,16.5,0,0,1-1.08,3.66c-2-.36-4-.66-5.94-1-.6,1.26-1.14,2.52-1.74,3.78a8.53,8.53,0,0,1-3.54-1.74c.3-1,.6-2,1-2.88-5.76-1.14-11.46-2.46-17.16-4,1.14-3.42,2.28-6.66,3.48-9.78-3,.18-6,.3-8.87.36a21.4,21.4,0,0,1-.37-4c3.66-.24,7.32-.42,10.92-.66q1.62-4.23,3.42-8.1a31.59,31.59,0,0,1,4,1.32c-.78,2.16-1.56,4.32-2.28,6.48.6,0,1.2-.06,1.8-.12,5.88-.3,11.94-.54,18.06-.72A9.87,9.87,0,0,1,288.79,389.26ZM270.25,372.4c-.18-2-.24-4.08-.24-6.18.72-.06,1.5-.12,2.4-.24a19.25,19.25,0,0,1,2.16.12c0,2.16.06,4.26.06,6.42q8.64.18,17.1.54.36,5.4.36,10.26a4.82,4.82,0,0,1-1.8.24,14.21,14.21,0,0,1-2.1-.12c-.24-1.38-.48-3.66-.72-6.78-9.24,0-18.6-.24-28-.72a6.39,6.39,0,0,1-.24-2,8.5,8.5,0,0,1,.12-1.68C263,372.28,266.65,372.34,270.25,372.4Z" 
  42.                 transform="translate(-245.6 -293.92)" /> 
  43.             <path class="svg-path path3" 
  44.                 d="M263.41,455.92c-5.46,2.88-10.74,5.46-15.89,7.68a6.9,6.9,0,0,1-1.92-3.18,175.82,175.82,0,0,1,15.83-8.34A16.66,16.66,0,0,1,263.41,455.92Zm9.66-15.9h7.38a87,87,0,0,1,9,.42,6.32,6.32,0,0,1,.18,1.8,5.26,5.26,0,0,1-.18,1.8c-.6.24-3.6.3-9,.3-18.06,0-27.9-.06-29.51-.3a5.28,5.28,0,0,1-.25-1.92,4.33,4.33,0,0,1,.31-1.86l17.75-.18a30.6,30.6,0,0,1-.48-4q1.8-.27,4-.54C272.59,437,272.83,438.52,273.07,440Zm-13.26,35.34a9.85,9.85,0,0,1-3.66.66,56.49,56.49,0,0,1-3-13,16.28,16.28,0,0,1,3.48-.72A65.47,65.47,0,0,1,259.81,475.36Zm8.1-10.32a8.29,8.29,0,0,1-3.18-2.22,65.29,65.29,0,0,1,11.4-13.26,11.4,11.4,0,0,1,2.7,2.1c-.48.72-1,1.5-1.56,2.22,4.5,1.32,9.3,2.82,14.46,4.5-1.68,4.8-3.54,9.42-5.46,13.86-.78,1.86-1.5,3.48-2.1,4.86,2.52,1,5,2,7.38,3a20.4,20.4,0,0,1-1.38,3.42c-2.64-.78-5.16-1.62-7.68-2.52a26.33,26.33,0,0,1-2,3.9,10.66,10.66,0,0,1-3.84-1.74c.48-1.26,1-2.52,1.56-3.72-3.48-1.26-7-2.64-10.38-4.2a13.37,13.37,0,0,1,1.38-3.78c3.6,1.32,7.2,2.64,10.74,4,2.1-4.92,4.14-9.78,6.18-14.58-4.08-1.14-7.86-2.34-11.34-3.66C272.77,459.58,270.49,462.22,267.91,465Zm12.54,1.14a14.75,14.75,0,0,1-1.5,3.3,19,19,0,0,1-6.3-2.76,17.21,17.21,0,0,1,1.56-3.48C276.31,464.14,278.41,465.1,280.45,466.18Z" 
  45.                 transform="translate(-245.6 -293.92)" /> 
  46.             <path class="svg-path path4" 
  47.                 d="M251.71,539a21.77,21.77,0,0,1-3.9.36c-.77-5.52-1.25-11-1.49-16.62a22,22,0,0,1,4.08-.36C250.94,528,251.35,533.62,251.71,539Zm7.8-14a64.55,64.55,0,0,1,6.54,1.08,20.77,20.77,0,0,1-.42,3.6,22.77,22.77,0,0,1-5.82-.66c.36,5.64.6,11.1.66,16.38a4.87,4.87,0,0,1-1.74.24,6.14,6.14,0,0,1-1.68-.12A261.61,261.61,0,0,1,255,515.8a11,11,0,0,1,1.92-.24h1.79C259,518.8,259.27,521.92,259.51,525Zm21.18-13.5a9.67,9.67,0,0,1,3.84,1.26c-.54,1.86-1.26,4.44-2.16,7.68,3,.06,6.18.18,9.66.36.36,3.24.72,7.5,1.14,12.9a13.74,13.74,0,0,1-4,.54c-.6-3.84-1-7.08-1.38-9.84-2.4,0-4.62-.06-6.6-.06-1,3.24-2,7-3.18,11.28h9.42a73.75,73.75,0,0,1,8.28.42,5.65,5.65,0,0,1,.18,1.68,4.47,4.47,0,0,1-.18,1.62c-.54.24-3.3.3-8.28.3H276.91c-1.08,3.84-2.28,8-3.48,12.42a11.64,11.64,0,0,1-3.6-1.26c.66-3.54,1.5-7.26,2.46-11.22a77,77,0,0,1-7.92-.24,7,7,0,0,1-.18-1.74,4.26,4.26,0,0,1,.3-1.74l8.76-.18c1-3.6,2.1-7.44,3.3-11.46-3-.06-5.52-.18-7.68-.3a14.37,14.37,0,0,1-.3-3.3c3.24-.12,6.3-.18,9.18-.24C278.65,517.48,279.61,514.48,280.69,511.48Zm11.22,36.06a9.05,9.05,0,0,1-.9,1.68,11.09,11.09,0,0,1-1.14,1.62,28.41,28.41,0,0,1-9.18-4.5,9.93,9.93,0,0,1,2.1-3.42C285.73,544.3,288.79,545.86,291.91,547.54Z" 
  48.                 transform="translate(-245.6 -293.92)" /> 
  49.             <path class="svg-path path5" 
  50.                 d="M255.19,591.4a66.44,66.44,0,0,1-.72,9.42c2.1.6,6.18,1,12.3,1.08-.42-3.72-.84-7.38-1.2-11.1a18.16,18.16,0,0,1,4.2-.6c.6,4,1.14,7.86,1.62,11.76,9.12,0,15.36-.3,18.6-.9a17.86,17.86,0,0,1,.48,4c-2.88,1.08-9,1.62-18.48,1.74q1.08,9.72,1.62,19.62a31.7,31.7,0,0,1-10.44,1.44,7.53,7.53,0,0,1-.84-3.42,44.52,44.52,0,0,1,6.84-.9c-.66-5.58-1.26-11.16-1.86-16.74-8.64-.12-14.52-.66-17.69-1.62a94.48,94.48,0,0,1,1-13.86,19.81,19.81,0,0,1,2.35-.12C254.42,591.34,255.19,591.4,255.19,591.4Zm32-7.92a14.29,14.29,0,0,1,.12,2q-18.54,2.61-36.77,3.9a4.47,4.47,0,0,1-.48-2.1v-1.8c12.35-1.56,24.59-2.76,36.83-3.72A6.24,6.24,0,0,1,287.17,583.48Zm-28.08,31c-1,3.12-2,6.6-3.36,10.38a8.26,8.26,0,0,1-4.14-1.32A55.78,55.78,0,0,1,255,613,20.2,20.2,0,0,1,259.09,614.5Zm29.16,2.28c.72,1.44,1.38,2.82,1.86,4.08a9.78,9.78,0,0,1-4,1.74,39.45,39.45,0,0,1-4.38-8.7,22.14,22.14,0,0,1,4.08-1.62C286.69,613.84,287.53,615.34,288.25,616.78Z" 
  51.                 transform="translate(-245.6 -293.92)" /> 
  52.         </svg> 
  53.         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 219.1 246.81"
  54.             <path class="svg-path path6" 
  55.                 d="M326.34,316.17h32.53l27.71,25.3,10.84,36.14V421l-9.64,37.35L376,486.05l-31.54,14.46-28.92-6-15.66-10.84-5.37,4.7-13.91,12.17H262.48l-30.12-10.85L201,471.59,186.58,433l-7.23-51.81,34.94-39.76,85.54,9.64Z" 
  56.                 transform="translate(-178.82 -254.22)" /> 
  57.             <path class="svg-path path7" 
  58.                 d="M243.2,296.89l-4.81-14.46L248,254.72h14.46l23.5,12,23.49,18.07v24.1l-9.64,42.17L262.48,321Z" 
  59.                 transform="translate(-178.82 -254.22)" /> 
  60.             <path class="svg-path path8" d="M248,254.72l18.29,24.63,23.87,40.7,9.65,31.06" 
  61.                 transform="translate(-178.82 -254.22)" /> 
  62.         </svg> 
  63.     </div> 
  64.  
  65.     <script> 
  66.         const duration = 800; 
  67.  
  68.         anime({ 
  69.             targets: ".svg-path"
  70.             strokeDashoffset: function(item) {  
  71.                 const svgLength = anime.setDashoffset(item);  
  72.                 return [svgLength, 0];  
  73.             }, 
  74.             easing: "linear"
  75.             duration, 
  76.             delay: function (item, index) { 
  77.                 return duration * index
  78.             }, 
  79.             updatefunction (anim) { 
  80.                 const color = ['red''pink''purple','skyblue''blue','red''green','green']; 
  81.                 for(let i = 1; i <= color.length; i++) { 
  82.                     if (anim.currentTime >= duration * i) { 
  83.                         document.querySelector(".path" + i).style.fill = color[i-1]; 
  84.                     } 
  85.                 } 
  86.             }, 
  87.             autoplay: true 
  88.         }); 
  89.     </script> 
  90.  
  91. </body> 
  92.  
  93. </html> 

总结

SVG 是网页里画矢量图的技术,可以用 rect、circle、line 等画一些具体的图形,也可以用 path 来画更复杂的图形。

SVG path 的 api 和 canvas 里的 path 差不多,比如 M 是 moveTo,L 是 lineTo,Z 是 closePath。

复杂图形可以用矢量图绘制软件 Illuastrator 来绘制,之后导出为 SVG。

SVG 可以设置的属性主要有 stroke 指定线条样式,fill 指定填充样式。

其中 stroke-dasharray 是指定虚线长度,stroke-dashoffset 是指定虚线偏移,正数向左,负数向右。

通过 stroke-dashoffset 的值的变化,就能实现描边的效果,从 SVG 的整体长度慢慢变化到 0。

属性值的修改可以用动画框架 anime.js,它支持定时修改元素的属性值来做动画,并且支持匀速、加速等时间函数。

文中的那个动画,我们指定每个 path 的 delay 时间,每个 path 绘制完之后设置 fill 属性即可。

SVG 的描边动画还是挺不错的效果,可以用在很多地方。实现原理也不难,就是一个 offset 属性值的修改。大家很快就能学会。

最后,再次祝大家平安夜快乐呀,加上今天是周五,double 的快乐~

 

责任编辑:姜华 来源: 神光的编程秘籍
相关推荐

2013-01-04 17:42:37

亚马逊宕机负载均衡

2009-12-25 17:50:04

2011-12-20 12:19:11

2010-12-24 18:12:02

系统升级

2014-12-25 17:07:00

2009-12-24 13:51:54

热门服务器

2021-02-21 08:12:24

SVG线条动画Web动画

2019-03-24 14:14:40

代码阅读源代码

2012-12-26 10:05:06

亚马逊云计算Netflix

2020-07-15 15:38:15

人脸识别照片活化手机

2018-03-09 10:28:30

生态报告签收

2022-04-29 08:48:25

开源

2021-02-21 07:49:40

Web动画SVG线条动画

2021-12-15 18:32:33

Log4Shell漏洞攻击

2015-03-19 15:17:11

2023-09-01 14:02:25

用户分析攻略

2016-08-24 16:55:18

DevOps结构清单

2023-09-29 22:41:26

Kubernetes云原生

2018-07-29 15:33:04

点赞
收藏

51CTO技术栈公众号