SVG动画,无需使用任何外部库。

huangapple go评论72阅读模式
英文:

SVG animation without using any external library

问题

这个SVG是否可以实现眨眼效果?如果可能的话,是否可以只使用CSS实现?

英文:

Is it possible to do the blinking eye effect from this SVG? If possible using CSS only.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

&lt;div style=&quot;background: black;padding: 20px;&quot;&gt;
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;134.527&quot; height=&quot;134.502&quot; viewBox=&quot;0 0 134.527 134.502&quot;&gt;
     &lt;defs&gt;
       &lt;clipPath id=&quot;clip-path&quot;&gt;
         &lt;rect id=&quot;Rectangle_527&quot; data-name=&quot;Rectangle 527&quot; width=&quot;134.527&quot; height=&quot;134.502&quot; fill=&quot;none&quot;/&gt;
       &lt;/clipPath&gt;
      &lt;/defs&gt;
      &lt;g id=&quot;Group_441&quot; data-name=&quot;Group 441&quot; clip-path=&quot;url(#clip-path)&quot;&gt;
       &lt;path id=&quot;Path_1157&quot; data-name=&quot;Path 1157&quot; d=&quot;M134.31,66.626A77.276,77.276,0,0,1,.3,66.817&quot; fill=&quot;none&quot; stroke=&quot;#fff&quot; stroke-width=&quot;1&quot;/&gt;
       &lt;circle id=&quot;Ellipse_25&quot; data-name=&quot;Ellipse 25&quot; cx=&quot;67.001&quot; cy=&quot;67.001&quot; r=&quot;67.001&quot; transform=&quot;translate(0.25 0.25)&quot; fill=&quot;none&quot; stroke=&quot;#fff&quot; stroke-width=&quot;1&quot;/&gt;
       &lt;path id=&quot;Path_1158&quot; data-name=&quot;Path 1158&quot; d=&quot;M.336,66.626a77.275,77.275,0,0,1,133.889.1&quot; fill=&quot;none&quot; stroke=&quot;#fff&quot; stroke-width=&quot;1&quot;/&gt;
       &lt;path id=&quot;Path_1159&quot; data-name=&quot;Path 1159&quot; d=&quot;M67.122,95.866a28.7,28.7,0,1,1,11.26-2.276,28.932,28.932,0,0,1-11.26,2.276m0-44.465h0c-1.232,4.832-2.378,8.063-4.592,10.276s-5.445,3.359-10.277,4.59c4.833,1.232,8.064,2.38,10.277,4.593s3.36,5.444,4.592,10.277c1.231-4.832,2.378-8.063,4.59-10.277s5.444-3.36,10.277-4.593c-4.833-1.231-8.064-2.378-10.277-4.59s-3.359-5.445-4.59-10.276&quot; fill=&quot;#9bd698&quot;/&gt;
      &lt;/g&gt;
    &lt;/svg&gt;
    &lt;/div&gt;

<!-- end snippet -->

答案1

得分: 1

你可以使用SVG动画与SMIL。在这里,<animate> 元素内部的路径来对路径的d属性进行动画。

<div style="background: black;padding: 20px;">
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="130" height="130" viewBox="0 0 122 122">
    <g transform="translate(1 1)">
      <path transform="translate(60 60)" d="M 0 23.7 a 23 23 90 1 1 9 -1.8 a 23.1 23.1 90 0 1 -9 1.8 m 0 -35.6 h 0 c -1 3.9 -1.9 6.5 -3.7 8.2 s -4.4 2.7 -8.2 3.7 c 3.9 1 6.5 1.9 8.2 3.7 s 2.7 4.4 3.7 8.2 c 1 -3.9 1.9 -6.5 3.7 -8.2 s 4.4 -2.7 8.2 -3.7 c -3.9 -1 -6.5 -1.9 -8.2 -3.7 s -2.7 -4.4 -3.7 -8.2" fill="#9bd698"/>
      <path d="M 120 60 Q 60 110 0 60 A 1 1 0 0 0 120 60 Z" fill="#000" stroke="#fff" stroke-width="1">
        <animate attributeName="d" repeatCount="indefinite" calcMode="linear" values="
        M 120 60 Q 60 110 0 60 A 1 1 0 0 0 120 60 Z;
        M 120 60 Q 60 110 0 60 A 1 1 0 0 0 120 60 Z;
        M 120 60 Q 60 60 0 60 A 1 1 0 0 0 120 60 Z;
        M 120 60 Q 60 60 0 60 A 1 1 0 0 0 120 60 Z;
        M 120 60 Q 60 110 0 60 A 1 1 0 0 0 120 60 Z"
        keyTimes="0;0.1;0.33;0.8;1" dur="4s" />
      </path>
      <path d="M 120 60 Q 60 10 0 60 A 1 1 0 0 1 120 60 Z" fill="#000" stroke="#fff" stroke-width="1">
        <animate attributeName="d" repeatCount="indefinite" values="
        M 120 60 Q 60 10 0 60 A 1 1 0 0 1 120 60 Z;
        M 120 60 Q 60 10 0 60 A 1 1 0 0 1 120 60 Z;
        M 120 60 Q 60 60 0 60 A 1 1 0 0 1 120 60 Z;
        M 120 60 Q 60 60 0 60 A 1 1 0 0 1 120 60 Z;
        M 120 60 Q 60 10 0 60 A 1 1 0 0 1 120 60 Z"
        keyTimes="0;0.1;0.33;0.8;1" dur="4s" />
      </path>
    </g>
  </svg>
</div>
英文:

You can use SVG animation with SMIL. Here, the &lt;animate&gt; element inside the path to animate the d attribute of the path.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

&lt;div style=&quot;background: black;padding: 20px;&quot;&gt;
  &lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;130&quot; height=&quot;130&quot; viewBox=&quot;0 0 122 122&quot;&gt;
    &lt;g transform=&quot;translate(1 1)&quot;&gt;
      &lt;path transform=&quot;translate(60 60)&quot; d=&quot;M 0 23.7 a 23 23 90 1 1 9 -1.8 a 23.1 23.1 90 0 1 -9 1.8 m 0 -35.6 h 0 c -1 3.9 -1.9 6.5 -3.7 8.2 s -4.4 2.7 -8.2 3.7 c 3.9 1 6.5 1.9 8.2 3.7 s 2.7 4.4 3.7 8.2 c 1 -3.9 1.9 -6.5 3.7 -8.2 s 4.4 -2.7 8.2 -3.7 c -3.9 -1 -6.5 -1.9 -8.2 -3.7 s -2.7 -4.4 -3.7 -8.2&quot; fill=&quot;#9bd698&quot;/&gt;
      &lt;path d=&quot;M 120 60 Q 60 110 0 60 A 1 1 0 0 0 120 60 Z&quot; fill=&quot;#000&quot;
        stroke=&quot;#fff&quot; stroke-width=&quot;1&quot;&gt;
        &lt;animate attributeName=&quot;d&quot; repeatCount=&quot;indefinite&quot; calcMode=&quot;linear&quot; values=&quot;
        M 120 60 Q 60 110 0 60 A 1 1 0 0 0 120 60 Z;
        M 120 60 Q 60 110 0 60 A 1 1 0 0 0 120 60 Z;
        M 120 60 Q 60 60 0 60 A 1 1 0 0 0 120 60 Z;
        M 120 60 Q 60 60 0 60 A 1 1 0 0 0 120 60 Z;
        M 120 60 Q 60 110 0 60 A 1 1 0 0 0 120 60 Z&quot;
        keyTimes=&quot;0;0.1; 0.33;0.8;1&quot; dur=&quot;4s&quot; /&gt;
      &lt;/path&gt;
      &lt;path d=&quot;M 120 60 Q 60 10 0 60 A 1 1 0 0 1 120 60 Z&quot; fill=&quot;#000&quot;
        stroke=&quot;#fff&quot; stroke-width=&quot;1&quot;&gt;
        &lt;animate attributeName=&quot;d&quot; repeatCount=&quot;indefinite&quot; values=&quot;
        M 120 60 Q 60 10 0 60 A 1 1 0 0 1 120 60 Z;
        M 120 60 Q 60 10 0 60 A 1 1 0 0 1 120 60 Z;
        M 120 60 Q 60 60 0 60 A 1 1 0 0 1 120 60 Z;
        M 120 60 Q 60 60 0 60 A 1 1 0 0 1 120 60 Z;
        M 120 60 Q 60 10 0 60 A 1 1 0 0 1 120 60 Z&quot;
        keyTimes=&quot;0;0.1;0.33;0.8;1&quot; dur=&quot;4s&quot; /&gt;
      &lt;/path&gt;
    &lt;/g&gt;
  &lt;/svg&gt;
&lt;/div&gt;

<!-- end snippet -->

答案2

得分: 1

SVG SMIL动画目前可能是最好的跨浏览器解决方案,正如**chrwahl**所建议的。

未来的方法:通过CSS path()来变换路径

截止到目前(2023年),Safari不支持此功能。 但是,我们可能会在未来几年看到更好的支持。

<svg id="svg1" xmlns="http://www.w3.org/2000/svg" width="134.527" height="134.502" viewBox="0 0 134.5 134.5">

    <path id="pupil" d="M 67.1 95.9 a 28.7 28.7 0 1 1 11.3 -2.3 a 28.9 28.9 0 0 1 -11.3 2.3z 
    m 0 -44.5 h 0 c -1.2 4.8 -2.4 8.1 -4.6 10.3 s -5.4 3.4 -10.3 4.6 c 4.8 1.2 8.1 2.4 10.3 4.6 s 3.4 5.4 4.6 10.3 c 1.2 -4.8 2.4 -8.1 4.6 -10.3 s 5.4 -3.4 10.3 -4.6 c -4.8 -1.2 -8.1 -2.4 -10.3 -4.6 s -3.4 -5.4 -4.6 -10.3z" fill="#9bd698" />

    <path id="eyelid__top" class="eyelids" d="
    M0 67.25 
    A 67.25 67.25 0 0 1 134.5 67.25
    A 77 77 0 0 0 0 67.25 z"  />
      

    <path class="eyelids" id="eyelid__bottom" d="
    M0 67.25 
    A 67.25 67.25 0 0 0 134.5 67.25 
    A 77 77 0 0 1 0 67.25 z                                                    
    "  />

</svg>

路径兼容性

为了进行形状"变形"插值,两条路径需要完全兼容,即:

  • 具有完全相同的命令数
  • 使用相同的命令类型(例如,VHST等简写形式不能与其对应的路径使用“长手”等效形式,如LCQ
  • 相应路径段不能在相对和绝对命令之间切换
  • 圆弧命令中的长弧和扫描标志:这些值是布尔值,只能是1或0:

因此,我们不能在插值过程中切换这些参数。例如:

M0 50 A 50 50 0 0 0 100 50

M0 50 A 50 50 0 1 1 100 50

不能进行过渡/插值。

相同的规则适用于SVG SMIL动画。

英文:

Currently, SVG SMIL animation is probably the best cross-browser solution - as suggested by chrwahl.

Future approach: morph paths via css path()

This is currently (2023) not supported in safari.
However, we might see better support in the next years.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

body {
  background: #000;
}

svg {
  overflow: visible;
}

.eyelids {
  stroke: #fff;
  stroke-width: 1px;
}

#eyelid__top {
  animation: closeEye1 1s infinite forwards;
}

#eyelid__bottom {
  animation: closeEye2 1s infinite forwards;
}

@keyframes closeEye1 {
  0% {
    d: path(&quot;M0 67.25 A 67.25 67.25 0 0 1 134.5 67.25A 77 77 0 0 0 0 67.25 z&quot;);
  }
  20% {
    d: path(&quot;M0 67.25 A 67.25 67.25 0 0 1 134.5 67.25A 77 0 0 0 0 0 67.25 z&quot;);
  }
  40% {
    d: path(&quot;M0 67.25 A 67.25 67.25 0 0 1 134.5 67.25A 77 77 0 0 0 0 67.25 z&quot;);
  }
}

@keyframes closeEye2 {
  0% {
    d: path(&quot;M0 67.25 A 67.25 67.25 0 0 0 134.5 67.25 A 77 77 0 0 1 0 67.25 z &quot;);
  }
  20% {
    d: path(&quot;M0 67.25 A 67.25 67.25 0 0 0 134.5 67.25 A 77 0 0 0 1 0 67.25 z &quot;);
  }
  40% {
    d: path(&quot;M0 67.25 A 67.25 67.25 0 0 0 134.5 67.25 A 77 77 0 0 1 0 67.25 z &quot;);
  }
}

.active {
  fill: red
}


/*
#eyelid__top{
  d: path(&quot;M 0 67.25 C 0 15.48 56.04 -16.87 100.88 9.01 C 121.68 21.02 134.5 43.22 134.5 67.25 C 105.63 15.48 31.55 14.38 1.15 65.26 C 0.75 65.92 0.37 66.58 0 67.25 Z&quot;)
}

#eyelid__top.active{
  d: path(&quot;M 0 67.25 C 0 15.48 56.04 -16.87 100.88 9.01 C 121.68 21.02 134.5 43.22 134.5 67.25 C 105.63 119.02 31.55 120.12 1.15 69.24 C 0.75 68.58 0.37 67.92 0 67.25 Z&quot;);
}

#eyelid__bottom{
  d: path(&quot;M 0 67.25C 0 119.02 56.04 151.37 100.88 125.49C 121.68 113.48 134.5 91.28 134.5 67.25C 105.63 119.02 31.55 120.12 1.15 69.24C 0.75 68.58 0.37 67.92 0 67.25Z&quot;)
}

#eyelid__bottom.active{
  d: path(&quot;M0 67.25C0 119.02 56.04 151.37 100.88 125.49C121.68 113.48 134.5 91.28 134.5 67.25C105.63 53.8 31.55 53.52 1.15 66.73C0.75 66.9 0.37 67.08 0 67.25Z&quot;);
}

*/


/*
svg:hover
#eyelid__top{
  d: path(&quot;M 0 67.25 C 0 15.48 56.04 -16.87 100.88 9.01 C 121.68 21.02 134.5 43.22 134.5 67.25 C 105.63 119.02 31.55 120.12 1.15 69.24 C 0.75 68.58 0.37 67.92 0 67.25 Z&quot;);
}

svg:hover
#eyelid__bottom{
  d: path(&quot;M0 67.25C0 119.02 56.04 151.37 100.88 125.49C121.68 113.48 134.5 91.28 134.5 67.25C105.63 53.8 31.55 53.52 1.15 66.73C0.75 66.9 0.37 67.08 0 67.25Z&quot;);
}
*/

<!-- language: lang-html -->

&lt;svg id=&quot;svg1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;134.527&quot; height=&quot;134.502&quot; viewBox=&quot;0 0 134.5 134.5&quot;&gt;

    &lt;path id=&quot;pupil&quot; d=&quot;M 67.1 95.9 a 28.7 28.7 0 1 1 11.3 -2.3 a 28.9 28.9 0 0 1 -11.3 2.3z 
m 0 -44.5 h 0 c -1.2 4.8 -2.4 8.1 -4.6 10.3 s -5.4 3.4 -10.3 4.6 c 4.8 1.2 8.1 2.4 10.3 4.6 s 3.4 5.4 4.6 10.3 c 1.2 -4.8 2.4 -8.1 4.6 -10.3 s 5.4 -3.4 10.3 -4.6 c -4.8 -1.2 -8.1 -2.4 -10.3 -4.6 s -3.4 -5.4 -4.6 -10.3z&quot; fill=&quot;#9bd698&quot; /&gt;

&lt;path id=&quot;eyelid__top&quot; class=&quot;eyelids&quot; d=&quot;
M0 67.25 
A 67.25 67.25 0 0 1 134.5 67.25
A 77 77 0 0 0 0 67.25 z&quot;  /&gt;
  

&lt;path class=&quot;eyelids&quot; id=&quot;eyelid__bottom&quot; d=&quot;
M0 67.25 
A 67.25 67.25 0 0 0 134.5 67.25 
A 77 77 0 0 1 0 67.25 z                                                    
&quot;  /&gt;

&lt;/svg&gt;

<!-- end snippet -->

Path compatibility

For shape "morphing" interpolation both paths need to be perfectly compatible i.e:

  • have the exact same number of commands
  • use the same command types (shorthands like V, H, S or T won't work if their correspondend path uses "longhand" equivalents like L,C or Q
  • correspondent path segments can't switch between relative and absolute commands
  • long arc and sweep flag in Arc commands: These values are boolean and can only be 1 or 0:

So we can't switch these parameters during interpolation. E.g:

M0 50 A 50 50 0 0 0 100 50  

to

M0 50 A 50 50 0 1 1 100 50  

can't be transitioned/interpolated.

The same rules apply to SVG SMIL animations.

答案3

得分: 0

你可以经常使用一些小技巧来获得不错的效果,比如拉伸或缩小元素。在这种情况下,我理解你想要关闭眼皮并使瞳孔消失。关闭眼皮的简单方法是将它们垂直缩小到中心。但这还不够。你还需要缩小另一个剪裁瞳孔的元素,使其在眼皮关闭时消失。在这个例子中,我添加了一个clipPath#cPath_1157),它与眼皮的相同(后面会详细说明),并使用相同的参数进行动画处理:

.blink{
  animation: frombot 0.3s linear 1s 10;
  transform-origin: 0;
  animation-direction: alternate;
}

@keyframes frombot{
  to{
    transform: scaleY(0)
  }
}
<div style="background: black;padding: 20px;">
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="134.527" height="134.502" viewBox="0 0 134.527 134.502">
    <!-- 省略部分 -->
  </svg>
</div>

一些建议:

  • 眼皮和clipPath之间存在小差异,所有浏览器都存在。这表明我没有考虑到clip-path实现中的某些细节。

  • 我还修改了眼皮的代码。你之前有两条路径,我将它们合并成一条,这样会大大简化动画。

英文:

You can often get nice effects with little tricks, like stretching or shrinking elements. In this case, I understand that you want to close the lids and make the pupil disappear. A simple way to close the lids is to shrink them vertically towards the center. But this would not be enough. You also need to shrink an additional element that clips the pupil, so that it disappears as the lids close. In this example, I have added a clipPath (#cPath_1157) that is identical to that of the lids (more on that below) and is animated with the same parameters:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-css -->

.blink{
  animation: frombot 0.3s linear 1s 10;
  transform-origin: 0;
  animation-direction: alternate;
}

@keyframes frombot{
  
  to{
    transform: scaleY(0)
  }
}

<!-- language: lang-html -->

&lt;div style=&quot;background: black;padding: 20px;&quot;&gt;
&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; xmlns:xlink=&quot;http://www.w3.org/1999/xlink&quot; width=&quot;134.527&quot; height=&quot;134.502&quot; viewBox=&quot;0 0 134.527 134.502&quot;&gt;
     &lt;defs&gt;
       &lt;clipPath id=&quot;clip-path&quot;&gt;
         &lt;rect id=&quot;Rectangle_527&quot; data-name=&quot;Rectangle 527&quot; width=&quot;134.527&quot; height=&quot;134.502&quot; fill=&quot;none&quot;/&gt;
       &lt;/clipPath&gt;
       &lt;clipPath id=&quot;bl1&quot; class=&quot;blink&quot;&gt;
         &lt;path id=&quot;cPath_1157&quot; class=&quot;blink&quot; data-name=&quot;PathC1157&quot; d=&quot;M134.31,66.626A77.276,77.276,0,0,1,.3,66.817A77.276,77.276,0,0,1,134.31,66.626Z&quot; fill=&quot;none&quot; stroke=&quot;#fff&quot; stroke-width=&quot;1&quot;/&gt;
       &lt;/clipPath&gt;
      &lt;/defs&gt;
      &lt;g id=&quot;Group_441&quot; data-name=&quot;Group 441&quot; clip-path=&quot;url(#clip-path)&quot;&gt;
       &lt;path id=&quot;Path_1157&quot; class=&quot;blink&quot; data-name=&quot;Path 1157&quot; d=&quot;M134.31,66.626A77.276,77.276,0,0,1,.3,66.817A77.276,77.276,0,0,1,134.31,66.626Z&quot; fill=&quot;none&quot; stroke=&quot;#fff&quot; stroke-width=&quot;1&quot;/&gt;
       &lt;circle id=&quot;Ellipse_25&quot; data-name=&quot;Ellipse 25&quot; cx=&quot;67.001&quot; cy=&quot;67.001&quot; r=&quot;67.001&quot; transform=&quot;translate(0.25 0.25)&quot; fill=&quot;none&quot; stroke=&quot;#fff&quot; stroke-width=&quot;1&quot;/&gt;
       
       &lt;path id=&quot;Path_1159&quot; clip-path=&quot;url(#bl1)&quot; data-name=&quot;Path 1159&quot; d=&quot;M67.122,95.866a28.7,28.7,0,1,1,11.26-2.276,28.932,28.932,0,0,1-11.26,2.276m0-44.465h0c-1.232,4.832-2.378,8.063-4.592,10.276s-5.445,3.359-10.277,4.59c4.833,1.232,8.064,2.38,10.277,4.593s3.36,5.444,4.592,10.277c1.231-4.832,2.378-8.063,4.59-10.277s5.444-3.36,10.277-4.593c-4.833-1.231-8.064-2.378-10.277-4.59s-3.359-5.445-4.59-10.276&quot; fill=&quot;#9bd698&quot;/&gt;
      &lt;/g&gt;
  
    &lt;/svg&gt;
    &lt;/div&gt;

<!-- end snippet -->

A couple of points:

  • There is a small discrepancy between the lids and the clipPath. It is present in all the browsers. This suggests that there is a detail in the implementation of clip-path that I have not taken into account.

  • I have also changed the code for the lids. You had two paths and I have fused them into one, as it greatly simplifies the animation.

huangapple
  • 本文由 发表于 2023年6月1日 04:12:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376943.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定