The State of SVG Animation
Last updated 21st August 2013
Introduction
This page is a summary of the state of animation in SVG. Three methods are used for animation: SMIL, CSS Animations, and JavaScript. The SVG images are in separate files, added via <img> or <object> tags. The test image is loosely based on a simple Flash animated bar graph as found here. Tested with Firefox 23, Chrome 28, and Opera 12 on Linux.
Animation via SMIL
Simplest method.
Not natively supported by IE (and never will be). Can use FakeSmile for IE. This won't work with <img> tag as <img> doesn't allow use of JavaScript.
Reloading HTML page does not restart animation in Firefox and
Chrome. One must explicitly force the image to reload via, for
example,
onclick="getElementById('image_smil').src='flash_bars_smil.svg'"
for Firefox and
onclick="getElementById('image_smil').src='flash_bars_smil.svg?'+new Date().getMilliseconds()"
for Chrome.
(Aside: neither form works with Opera.)
Click image to reload. (Opera, reload page.)
Animation via CSS
Can't animate bar width; as width is an SVG attribute, not a property (which means you can't set it via CSS). Could possibly simulate by animating gradient stops.(?)
Reloading HTML page does not restart animation in Firefox and Chrome (works locally). One must explicitly force the image to reload. Both Firefox and Chrome require the "date" trick as used for Chrome above. When reloading the page this way in Chrome, the SVG text is slightly narrower(!).
Click image to reload. (Opera: reload page.)
Animation via JavaScript
Most complicated... but if you are creating SVG via JavaScript to begin with, maybe not so bad. Cannot use an <img> tag to embed SVG with JavaScript. Must use <object>, <embed>, or <iframe>. (Aside: Firefox and Opera don't use the 'height' property on <object> to reserve space when laying out page.)
Animation will restart when page is reloaded. With the <object> tag, the image steals clicks. This can be prevented in Firefox but not Chrome and Opera by adding pointer-events="none" to the SVG root element.
Firefox: Click the image to reload.
Opera: Click to left or right of image to reload (onclick
is set on wrapping <div>).
Chrome: Right click on image and select Reload to reload.
Summary
SMIL was the easiest way to animate the SVG followed by CSS and then JavaScript. I would probably choose SMIL after verifying that FakeSmile can take care of IE. One would have to use the <object> tag in that case.
Chrome's animation is smooth, Opera (v12) is OK, Firefox is quite rough and needs some work.
This exercise took way longer that it should have, two full days in fact. The problem wasn't the raw coding but dealing with the inconsistencies in the way browsers handle SVG. Hopefully, there will be more consistency in the future.
A summary of the pain points in rough order of pain caused:
- Can't animate bar width (CSS).
- Animations (SMIL, CSS) are not restarted when page is reloaded (Chrome, Firefox).
- Animations are not smooth (Firefox). I spent some time trying to at least get the JavaScript version smooth. The main problem turns out to be the use of an SVG filter for the rough textured background.
- The unanimated bar width must be set to 0px or the bar will be shown before the start of the animation (SMIL). This prevents having a proper fallback drawing in the case SMIL is not supported. (The CSS property 'animation-fill-mode' has a value 'both' which handles this.)
- No JavaScript with <image> tag forcing use of <object> tag.
- Can't prevent SVG from stealing mouse clicks when using <object> (Chrome, Opera).
- <object> 'height' property not used to reserve space during page layout resulting in page jumping when reloading HTML (Firefox, Opera).
- Image sizing different between <image> and <object> if 'viewBox' not given.
- Google+ doesn't use SVG images in post preview. (Nor could I force it to use a hidden PNG.)
One final thought... how does one make this type of drawing accessible? It seems the only way to do so is to include the data in the <image> 'alt' attribute.