Search code examples
cssanimationcss-animationssvg-animatesmil

SMIL to CSS Animation: multiple animations on single element


Now that SMIL is dying I want to convert my simple animated SVGs to using CSS Animations, but I am not super sure how to do the mapping. In this specific svg there are two animation elements.

#embedded {
  color: red;
 }
   <svg id="embedded"  xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
        <circle cx="50" cy="50" r="45" stroke="rgba(43,43,43,0.3)" fill="none" stroke-width="10" stroke-linecap="round"/>
        <circle cx="50" cy="50" r="45" stroke="currentColor" fill="none" stroke-width="6" stroke-linecap="round">
            <animate attributeName="stroke-dashoffset" dur="2s" repeatCount="indefinite" from="0" to="502"/>
            <animate attributeName="stroke-dasharray" dur="2s" repeatCount="indefinite" values="150.6 100.4;1 250;150.6 100.4"/>
        </circle>
    </svg>

While I seemingly started out fine with these css rules I quickly got stuck

stroke-dasharray: 150.6 100.4 1 250 150.6 100.4;
animation-duration: 2s;
animation-iteration-count: infinite;
stroke-dashoffset: ?;

What would a complete mapping be like? Is it possible at all? Sara Soueidan says not all animations are possible using CSS that are possible using SMIL.


Solution

  • The below is how you'd convert that SMIL animation into its equivalent CSS animation:

    • Both your animate tags have the dur="2s" and so the CSS animation's duration (animation-duration) would also be 2s. You can either specify this value using the long-hand property or using the short-hand property like in the below snippet.
    • There is no calcMode attribute specified for your animate element and so the interpolation mode is linear. Since the interpolation mode is linear, the animation-timing-function will also be linear.
    • The repeatCount is indefinite and so the animation-iteration-count will be infinite.
    • For the stroke-dashoffset, the animation has only a from (0%) and a to (100%) value. So, in the CSS animation's keyframes, we specify the stroke-dashoffset as 0 (from value) at 0% and as 502 (to value) at 100%.
    • For the stroke-dasharray, the animation makes use of values instead of just from and to. In this case, there are three semi-colon separated values and so the first value from the list is given within the 0% keyframe , the second value from the list is given at 50% keyframe and the last is given within the 100% keyframe selector.

    #embedded, #embedded2 {
      color: red;
      width: 200px;
      height: 200px;
    }
    #embedded circle#animated {
      animation: demo 2s infinite linear;
    }
    @keyframes demo {
      0% {
        stroke-dashoffset: 0;
        stroke-dasharray: 150.6 100.4;
      }
      50% {
        stroke-dasharray: 1 250;
      }
      100% {
        stroke-dashoffset: 502;
        stroke-dasharray: 150.6 100.4;
      }
    }
    <svg id="embedded" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
      <circle cx="50" cy="50" r="45" stroke="rgba(43,43,43,0.3)" fill="none" stroke-width="10" stroke-linecap="round" />
      <circle cx="50" cy="50" r="45" stroke="currentColor" fill="none" stroke-width="6" stroke-linecap="round" id="animated">
      </circle>
    </svg>
    
    <svg id="embedded2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
      <circle cx="50" cy="50" r="45" stroke="rgba(43,43,43,0.3)" fill="none" stroke-width="10" stroke-linecap="round" />
      <circle cx="50" cy="50" r="45" stroke="currentColor" fill="none" stroke-width="6" stroke-linecap="round">
        <animate attributeName="stroke-dashoffset" dur="2s" repeatCount="indefinite" from="0" to="502" />
        <animate attributeName="stroke-dasharray" dur="2s" repeatCount="indefinite" values="150.6 100.4;1 250;150.6 100.4" />
      </circle>
    </svg>