使用CSS动画SVG:先描边,再填充。

3

我完全不了解使用CSS对SVG进行动画处理(据我所知,JS可能也需要用到才能获得总路径长度),我需要实现以下效果:http://gph.is/2iZZ3Hw

<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 viewBox="0 0 47.4 47.7" style="enable-background:new 0 0 47.4 47.7;" xml:space="preserve">
<style type="text/css">
    .st0{fill-rule:evenodd;clip-rule:evenodd;fill:none;stroke:#FEC558;stroke-width:0.5;stroke-miterlimit:22.9256;}
    .st1{fill:#FFC656;}
</style>
<path class="st0" d="M23.7,45.8c12.1,0,22-9.9,22-22c0-12.1-9.9-22-22-22c-12.1,0-22,9.9-22,22C1.7,35.9,11.6,45.8,23.7,45.8z"/>
    <g>
        <polygon class="st1" points="14.1,17.9 14.1,20.2 14.1,22.2 14.1,23.4 14.1,24.7 14.1,27.6 32.7,35.2 32.7,32.5 32.7,30.7 
    32.7,29.7 32.7,28.5 32.7,25.2   "/>
        <polygon class="st1" points="19.2,18.7 24.3,20.6 27.5,21.9 27.5,21.2 27.5,19.4 27.5,17.5 27.5,16.3 27.5,15.2 27.5,12.5 
    15.5,17.2 19.2,18.7     "/>
    </g>
</svg>

https://css-tricks.com/svg-line-animation-works/ 介绍了如何对 SVG 描边进行动画处理。是的,需要使用 JS 来计算路径长度。 - Jonathan Nicol
2个回答

8

SVG animation

<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="30%" height="30%" viewBox="0 0 47.4 47.7" style="enable-background:new 0 0 47.4 47.7;" xml:space="preserve">
<style type="text/css">
    .st0{fill-rule:evenodd;clip-rule:evenodd;fill:none;stroke:#FEC558;stroke-width:0.5;stroke-miterlimit:22.9256;}
    .st1{fill:#FFC656;}
</style>
<defs>
<linearGradient id="grad" x1="0%" y1="0%" x2="0%" y2="100%" >
         
            <stop offset="0%" stop-color="#33363D"/>
            <stop offset="100%" stop-color="#5B5D5A"/>
</lineargradient>
</defs> 
<rect width="100%" height="100%" fill="url(#grad)"/>

<path id="circle" class="st0" stroke-dashoffset="138" stroke-dasharray="138" d="M23.7,45.8c12.1,0,22-9.9,22-22c0-12.1-9.9-22-22-22c-12.1,0-22,9.9-22,22C1.7,35.9,11.6,45.8,23.7,45.8z">
<animate id="an_circle" attributeName="stroke-dashoffset" values="138;0" dur="2s" fill="freeze" />
</path>
    <g stroke-width="0.5">
       <path id="trap" class="st1" stroke-dashoffset="60" stroke-dasharray="60" style="fill:none; stroke:#FEC558;" d="M14.1,17.9 14.1,20.2 14.1,22.2 14.1,23.4 14.1,24.7 14.1,27.6 32.7,35.2 32.7,32.5 32.7,30.7  32.7,29.7 32.7,28.5 32.7,25.2z">
        <animate id="an_trap" attributeName="stroke-dashoffset" values="60;0" dur="1s" fill="freeze" />
        <animate id="fill_trap" attributeName="fill" values="#33363D;#FEC558"  begin="an_circle.end" dur="1s" fill="freeze" />
     </path>
        <path id="triangle" class="st1" stroke-dashoffset="35" stroke-dasharray="35" style="fill:none; stroke:#FEC558;"  d="M19.2,18.7 24.3,20.6 27.5,21.9 27.5,21.2 27.5,19.4 27.5,17.5 27.5,16.3 27.5,15.2 27.5,12.5 15.5,17.2 19.2,18.7">
        
        <animate id="an_triangle" attributeName="stroke-dashoffset" begin="an_trap.end" values="35;0" dur="1s" fill="freeze" />
          <animate id="fill_triangle" attributeName="fill" values="#33363D;#FEC558"  begin="fill_trap.end-0.5s" dur="1s" fill="freeze" />
      </path>
    </g>
</svg>

  • 使用JS确定对象的长度
    <script>
             function TotalLength(){
              var path = document.querySelector('#circle');
            var len = Math.round(path.getTotalLength() );
            alert("path length - " + len);
            };
      </script>

路径长度:

圆形 - 138像素

梯形 - 60像素

三角形 - 35像素

  • 绘制对象动画的命令
<animate id="an_circle" attributeName="stroke-dashoffset"
   values="138;0" dur="2s" fill="freeze" />

  <animate id="an_trap" attributeName="stroke-dashoffset"
     values="60;0" dur="1s" fill="freeze" />

<animate id="an_triangle" attributeName="stroke-dashoffset" 
   begin="an_trap.end" values="35;0" dur="1s" fill="freeze" />
  • 当梯形的绘制动画完成时,三角形绘制动画将开始。

begin="an_trap.end"

  • 当圆形绘制动画结束时,梯形填充色动画将开始。
<animate id="fill_trap" attributeName="fill" values="#33363D;#FEC558"  
    begin="an_circle.end" dur="1s" fill="freeze" />
  • 当梯形的填充动画结束时,三角形的颜色填充动画将开始。
    <animate id="fill_triangle" attributeName="fill" values="#33363D;#FEC558"  
       begin="fill_trap.end-0.5s" dur="1s" fill="freeze" />

谢谢,这很好用。我会选择这个作为答案。如果我不想修改SVG代码怎么办?我能只用CSS3或JS实现吗?再次感谢! - Cristian C
1
@CristianC 是的。我可以用CSS动画替换SVG的Smill。我会尝试制作这个答案。 - Alexandr_TT

2

CSS解决方案

  • 使用CSS规则实现绘制形状轮廓的动画:

对于圆形

.circle {
    fill:none;
    stroke:#FEC558;
    stroke-dashoffset:138.5;
    stroke-dasharray:138.5;
    animation: circle_stroke 2s ease-in forwards;
        } 

    @keyframes circle_stroke {
    0% {
    stroke-dashoffset: 138.5;
    }
    100% {
    stroke-dashoffset: 0;
      }
    }    
  • 为梯形轮廓图形添加动画效果,并填充颜色

以下是代码

.trap {
    stroke-dashoffset:60;
    stroke-dasharray:60;
        animation:trap_stroke 2s ease-in-out forwards,  trap_fill  ease-in 3s forwards;

    }

    @keyframes trap_stroke {
    0% {
    stroke-dashoffset: 60.5;
    }

      100% {
    stroke-dashoffset: 0;
      }
    }  

    @keyframes trap_fill {
    0% {
    fill: none;
    }

      100% {
    fill: #FEC558;
      }
    }    

完整的动画代码

 .trap, .triangle {
   stroke:#FEC558;
   stroke-width:0.5;
 fill:none;
   }
 
 .circle {
 fill:none;
 stroke:#FEC558;
 stroke-dashoffset:138.5;
 stroke-dasharray:138.5;
 animation: circle_stroke 2s ease-in forwards;
  } 
 
 @keyframes circle_stroke {
 0% {
    stroke-dashoffset: 138.5;
 }
 100% {
    stroke-dashoffset: 0;
   }
 }
 

 
 
 .trap {
 stroke-dashoffset:60;
 stroke-dasharray:60;
  animation:trap_stroke 2s ease-in-out forwards,  trap_fill  ease-in 3s forwards;
 
 }
 
 @keyframes trap_stroke {
 0% {
    stroke-dashoffset: 60.5;
 }
    
   100% {
    stroke-dashoffset: 0;
   }
 }  
 
 @keyframes trap_fill {
 0% {
    fill: none;
 }
    
   100% {
    fill: #FEC558;
   }
 }  


 .triangle {
 stroke-dashoffset:35.5;
 stroke-dasharray:35.5;
 
 animation: triangle_stroke 1s ease-in-out forwards, triangle_fill 3.5s ease-in forwards;
 }  
 
 @keyframes triangle_stroke {
 0% {
    stroke-dashoffset: 35.5;
 }
 100% {
    stroke-dashoffset: 0;
   }
 }  
 
 @keyframes triangle_fill {
 0% {
    fill: none;
 }
 100% {
    fill: #FEC558;;
   }
 }
 
<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="30%" height="30%" viewBox="0 0 47.4 47.7" style="enable-background:new 0 0 47.4 47.7;" xml:space="preserve">  

<defs>
<linearGradient id="grad" x1="0%" y1="0%" x2="0%" y2="100%" >
         
            <stop offset="0%" stop-color="#33363D"/>
            <stop offset="100%" stop-color="#5B5D5A"/>
</lineargradient>
</defs> 
<rect width="100%" height="100%" fill="url(#grad)"/>

<path class="circle" d="M23.7,45.8c12.1,0,22-9.9,22-22c0-12.1-9.9-22-22-22c-12.1,0-22,9.9-22,22C1.7,35.9,11.6,45.8,23.7,45.8z"/>

    
       <path class="trap"    d="M14.1,17.9 14.1,20.2 14.1,22.2 14.1,23.4 14.1,24.7 14.1,27.6 32.7,35.2 32.7,32.5 32.7,30.7  32.7,29.7 32.7,28.5 32.7,25.2z" />
          
        <path class="triangle"   d="M19.2,18.7 24.3,20.6 27.5,21.9 27.5,21.2 27.5,19.4 27.5,17.5 27.5,16.3 27.5,15.2 27.5,12.5 15.5,17.2 19.2,18.7"/>
 

</svg>

演示

更新

适用于所有现代浏览器,除了IE

"IE10和IE11不支持媒体查询内的CSS关键帧块"。

(请参见“已知问题”)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接