最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 使用stroke-dashoffset 快速实现SVG描边动画

    正文概述 掘金(TTtttt)   2021-01-24   1083

    一、前言

    公司或者个人logo如何描边呢?我因为这个好奇地去调查了一番,发现了svg用几行代码就能搞定,于是我写下这篇文章,希望能快速帮助大家理解实现描边动画

    使用stroke-dashoffset 快速实现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 快速实现SVG描边动画

    • stroke-dashoffset:用于指定 stroke-dasharray 开始的偏移量,这也是动画的原理的关键

      我画个图帮助理解:

    使用stroke-dashoffset 快速实现SVG描边动画

    通过控制stroke-dashoffset 可以使得原本的图形发生偏移,让用户只能看到在框框中的图形。这时候再配合上css3的animation,设置偏移动画的时间和效果,就可以实现描边动画的效果

    • styleSheets:可以获取网页上引入的link样式表和style样式表。

      如果我们想要动态设置@keyframe,可以采用styleSheets的insertRule方法:

      • insertRule作用是来给当前样式表插入新的样式规则

      • insertRule(rule, index) 中第一个参数是必需的,代表要插入的新规则

      • 而index:可选,新规则插入的位置,样式表起始位置

    三、描边动画实现

    先举个简单的例子,如下图:

    使用stroke-dashoffset 快速实现SVG描边动画

    步骤:

    1. 我们先找设计师或者各大网站(比如这个例子我就是去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>
    
    1. 一般拿到svg的图片可能大小不合适,可以为它设置宽高

    2. 接着要设置stroke-dasharray的大小。

      重点

      • svg元素上有一个方法getTotalLength方法去获取到当前path的长度,是给stroke-dasharray赋值
      • 如果这时候有多个path元素,就去它们分别计算取最大值
      • 这里通过getTotalLength去取值,并且取最大值的原因是:
        1. 如果随便设置一个很大值,这时候如果业务场景需要不断地重复进行描边动画,这时候因为stroke-dasharray设置过大,会导致动画停留过久
        2. 而设置过小则因为stroke-dasharray方法是对图形切割的,会导致图形出现断层
          <script>
            document.addEventListener("DOMContentLoaded", () => {
              const logo = document.getElementsByClassName("icon-path")[0];
              console.log(logo.getTotalLength());
            });
          </script>
      
    3. 接着就是写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 是实现动画的关键,我们来介绍其中的几个比较容易忽略的属性
        1. linear这代表动画效果,可以参考animation-timing-function
        2. forwards 代表最后一帧是保持住当前图形而不用回到初始的时候。可以参考animation-fill-mode
        3. 这里animation 还可以设置数字或者infinite 代表重复次数或者无穷次,不设置则不重复,可以参考animation-iteration-count
        4. 2718是我经过getTotalLength去计算出的最大值。
        5. 0% 到 50% 是实现图形从无到有的形成过程, stroke-dashoffset设置为0代表展示图形
        6. 75%到100%的过程代表为图形上色的过程,这里的fill代表填充的颜色,这一般在拿到svg元素的就已经写在svg标签里了
    4. 到此整个流程结束,我们用一张图来总结吧:

    使用stroke-dashoffset 快速实现SVG描边动画

    四、进阶 | 通用设置

    通过上一章节我们已经知道了整个svg实现描边动画的步骤了,但是有一个新的问题产生了:如果我们svg图形色彩比较丰富,比较复杂了。我们还是手动一个一个为每个svg中的path元素去计算path长度,然后找到最大值吗?手动为每个path添加animation吗?这显然很不通用,也不是我们程序员该做的事。所以本篇将讲解更通用的设置:

    改善想法

    1. 当我们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;
            }
    
    1. 而要为每个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) 跑车

    使用stroke-dashoffset 快速实现SVG描边动画

    (2) 404

    使用stroke-dashoffset 快速实现SVG描边动画

    (3) 福

    使用stroke-dashoffset 快速实现SVG描边动画

    (4)呐喊

    使用stroke-dashoffset 快速实现SVG描边动画


    起源地 » 使用stroke-dashoffset 快速实现SVG描边动画

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元