Solving SVG animation issues

There are various ways to animate icons:

  • CSS animations using keyframes.
  • JavaScript animations. There are several libraries available to do that.
  • SVG animations.

This article is about the last method: animating icons using SVG animations level 2 spec.

No, it is not deprecated SMIL animations. It is a modern spec, though it is based on SMIL. Currenly it is supported by all modern browsers.

Sample

So what do SVG animations look like?

<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
   <g stroke="currentColor" stroke-linecap="round" stroke-linejoin="round">
       <path d="M3 14V5H21V19H3V14" fill="none" stroke-width="2" stroke-dasharray="66" stroke-dashoffset="66">
           <animate attributeName="stroke-dashoffset" values="66;0" dur="0.6s" fill="freeze" />
       </path>
       <path d="M3 16L7 13L10 15L16 10L21 14V19H3Z" fill="currentColor" fill-opacity="0" stroke-dasharray="52" stroke-dashoffset="52">
           <animate attributeName="stroke-dashoffset" values="52;0" begin="0.6s" dur="0.8s" fill="freeze" />
           <animate attributeName="fill-opacity" values="0;0.3" begin="1s" dur="0.15s" fill="freeze" />
       </path>
   </g>
   <circle cx="7.5" cy="9.5" r="1.5" fill="currentColor" fill-opacity="0">
       <animate attributeName="fill-opacity" values="0;1" begin="1s" dur="0.4s" fill="freeze" />
   </circle>
</svg>

This example uses <animate> tag to change attributes of parent elements over time. It changes stroke-dashoffset to animate stroke, so it looks like icon is being drawn and fill-opacity to fade in filled elements.

No CSS, no JavaScript, no external dependencies.

See <animate> documentation on MDN and SVG animations level 2 spec for more examples, other related tags, attributes.

Issues

Unfortunately, using animations is not that simple.

First of all, there are two ways to render SVGs:

  • Inline icons using <svg>.
  • External resources: SVG as URL or background image.

When using inline <svg>, animations cannot start until document is ready. It might seem like a small thing, but animations not rendering quickly enough can cause bad user experience. This issue can be caused by small things, such as statistics script failing to load or ad code loading slowly. If at least one server that page is loading resources from is unreachable, it might break all animated SVGs on page. Async and defer attributes do not help. Issue can even be caused by script in an iframe.

When using icon as URL, there is another issue: browser cache. If image is cached, some browsers do not restart animation.

Animation delay demo

Below is an <iframe> that shows icon rendering issue. It contains animated icon, rendered as <svg> and as background image. Both icons render instantly, but animation in <svg> does not start for few seconds because document is still loading.

To make things worse, this demo, which is in <iframe>, affects the main document. Logo on this page is rendered as <svg> and it contains animations. Refresh this page to see how slow script in a frame prevents SVG animations in unrelated icons in the main document.

Background bug demo

Below is an <iframe> that shows background bug.

Image is rendered as URL. If URL is already in browser cache, Chrome does not restart animation. That means consequent renders of the same animated icons can bug out.

Move mouse over demo to restart animation to see bug.

Is there a solution?

Solution to timing issue with inline <svg> is to use background image or mask.

Cache issue with background images can be solved by adding random content to icon, such as HTML comment with current time stamp before </svg>.

Below is an <iframe> that shows solution in action. It includes slowly loading script, which would break animation in inline <svg>, but does not break background images. Random content is dynamically added to solve Chrome cache issue.

Icon is rendered as mask, so icon could use currentColor, though background works too if you need to keep icon's palette.