The following is a guest post by Sarah Drasner (@sarah_edo). Sarah has been researching and giving talks about animation lately. I jumped at the chance to have her share some of that research here, this time focusing on SVG animation and the different tech choices you can make to do it.
After working with a number of SVG animation techniques for a few months now, I can give you a basic overview so you can compare them yourself. There are good reasons to use each one of these methods. Hopefully this post can point you to the right tool for the job.
We'll go through a basic comparison of features. Then we'll dig into how well they perform. Two different benchmarks are included. One is from recordings off the Chrome DevTools timeline, and the other is measuring visual recordings from the screen.
While HTML elements styled with CSS tend to perform better in animation, SVG has the advantage of being able to draw anything while being resolution independant. In the benchmarks, we're specifically working with SVG images.
We'll be comparing these SVG animation techniques:
High Level Comparisons
- It has good performance, especially when hardware accelerated, but perhaps not as good as the DevTools timeline reports. We'll touch on that later.
- It's easy to integrate in existing UI, as you don't need to load any other resources.
- CSS is perfect for small interactions like hover states.
- There are some good resources for more finely-tailored cubic-bezier easing, which makes it easy to visualize the potential outcome while developing.
- There are some backwards compatibility problems. @keyframes will not work on IE9 or lower.
- You can only create user interaction on pseudo state such as
- Chaining multiple animations is done with delays, which work well for simpler animations. For longer animations, this makes the workflow very complicated. It is difficult to adjust timescales, especially if you need to manipulate the first few frames.
- Physics can be cumbersome. Complicated tasks like friction, or a progressive decreasing bouncing ball are extremely complex at best and not an option at worst.
transform-originfor SVG is not consistent:
- Easy to use syntax. If you have existing jQuery animations, it’s easy to change them over to Velocity because it has the same style syntax. If you are used to
$.velocityis easy to work with.
- There are many out-of-the-box easings, and spring physics is available. For further refinements there is also step-easing where you can pass an array.
- The syntax is more concise than CSS or SMIL.
- You can stagger multiple animations with one line of code, particularly if you use the UI plugin available.
- Deeper browser support than CSS.
- Performs much better than existing jQuery
.animate()but not as well as CSS, SMIL, or GSAP.
- Offers backwards compatibility back to IE8, but not as far back as GSAP.
- Easy to use and the most compact syntax.
- The timeline for GSAP allows you to easily control and manipulate sequenced animation; this makes longer animations dramatically simpler to work with than pretty much any other technique. (You can set multiple tweens at the same point in time, create scenes, and move backwards and forwards, at different timescales- basically animate your animations).
- Automatically hardware accelerated. Performance is extremely good — as good as native rendering.
- Applying physics is simple. They have an ease visualizer that's pretty helpful.
- Has a solution to some known
- Offers support back to IE6. Better support than CSS, SMIL, or Velocity.
- GreenSock has a robust feature set. If you need to do something, GSAP has probably thought about it. To get a sense of what I'm saying, check out this robust plugins page, https://greensock.com/plugins/ most of which are included in the TweenMax version (though if you're worried about filesize, they have a lean, stripped down TweenLite version). There are some specialized features such as animating along a path (like SMIL can do with
<animateMotion>), drag/drop interactions, and even working with canvas.
- They have a jQuery plugin that will override the existing jQuery
.animate()and enhance performance with no extra coding necessary.
- Their code is open source, but you might need a license for commercial use in certain situations.
- Has a straightforward declarative syntax.
- You can morph paths and shapes using the same syntax with which it was written, which makes it very intuitive. This is nice for things like logos or morphing button icons.
- You can animate along a path.
- Performs very well, arguably better than CSS, Velocity, and GSAP in terms of visual display.
- There is non-delay based chaining like beginning an animation when another ends.
- Easy to add to existing SVG syntax and no need to load external resources.
- There is some speculation on whether support for SMIL will continue. Chrome is possibly introducing it into the Web Animations API (along with everything else), but if this doesn't go through it might not be well-maintained as it is currently underused.
- Chained animations are fairly limited.
- There is currently no support for IE.
In case IE browser support is a primary concern, here is a very simple breakdown:
There are a number of considerations when constructing a balanced benchmark across animation approaches. It needed to be a very simple SVG — I've used a rectangle with a stroke. Additionally, it needed to loop so that variations in performance over time could be observed. The benchmarking code can be found on GitHub, and also in this collection on CodePen.
Before you begin animating an SVG with any technique, it is best to optimize the SVG, just as you would with any other image. A couple of nice options are the in-browser SVG Editor or the node-based SVGO.
This is the hardware accelerated CSS version:
There are two different benchmarks included in this: one based on the Chrome DevTools timeline recordings, and one based on visual recordings off of the screen. This dual approach is necessary as Chrome may not be accurately reporting all processing in the timeline. Jack Doyle of GSAP does a good job of showing possible underreporting in this video.
Since the way that animations will be impacted will largely be the audience's interpretation of it's visual display, I've included a visual recording of the "jank" that can occur when running each along with the Chrome DevTools Timeline benchmarks. Jank is the amount of visual stutter that occurs when creating an animation or scroll event with the goal being silky smooth animations. If you would like to read more on this, JankFree is a great resource for tools and tips for optimizing your code.
Not All Demos are Created Equal - Hardware Acceleration and CPU
It's important in these comparisons to realize that simply building the animation with each method doesn't tell the whole story. With each technique, there are ways to hardware accelerate the animation to increase performance. In this demo, each technique is accelerated natively to the type of animation. For example, it is possible to optimize SMIL by giving the element its own layer in the compositor with CSS (e.g.
transform: translateZ(0)). But instead, I've shown how to do so directly inside SMIL. To demonstrate the performance delta, I've also left in a non-hardware-accelerated example of CSS and SMIL.
All code that was built from a library was proofed and approved by the library's author prior to testing.
How to hardware accelerate with CSS
- Setting transforms to null, and then moving them with transforms.
- You're offloading them to the GPU (Graphics Processing Unit). Most modern browsers ship with hardware acceleration, but don't use it until they are told they need to.
- Other GPU acceleration:
perspective: 1000;- keeps the animation from flickering.
- Isolate the layer you need to move or adjust.
- Move with transforms.
How to hardware accelerate with SMIL
<animate>and set x, y, z values (with 0 for z).
- Similar to CSS, this moves the element off to its own layer. Moving with transforms performs better than margins or top, left because it doesn't repaint.
How to hardware accelerate with Velocity
- Move with
translateY. Set the element to
- Make sure to avoid layout thrashing by declaring a variable for elements that you animate more than once to prevent multiple lookups (not applicable here but worth mentioning).
How to hardware accelerate with GSAP
- In the demo we set the element to
force3D: "true", but GSAP now ships with this automatically in place. This means you don't have to use
translateZ: 0;to hardware accelerate, it’s already included.
- Moving objects with X and Y perform better than margins.
- TweenLite is the lighter-weight version of GSAP, and it's recommended to use this for smaller animations. TweenMax offers support for loops, so we use it here.
A word to the wise: hardware accelerating too many layers at once can have an inverse effect. Each layer is a mapped GPU texture — having an excessive number will quickly exhaust available resources. Thus, it's important to use hardware-acceleration judiciously.
Here are the results from the timeline benchmarking: (the smaller bars indicate better performance.) Pay particular attention to “painting”, as this is the most costly of the events. Each benchmark was run 5 times to ensure consistency, then averaged. Included here is a version of CSS that is hardware accelerated (HA), and also where it is not (naive), to illustrate how significantly performance can be affected. These tests were run on Chrome Version 40.0.2214.91 (64-bit) — the latest stable release as of the article publication date. Please keep in mind that the version number can alter the timeline reporting.
Important Things to Note
Opacity and transform tend to perform better overall, and timeline reports them as being much better in hardware accelerated CSS:
Because of the aforementioned possibility of underreporting for CSS animations, it's important to weigh things not purely based on the timeline, but also what you see visually, as that is how the audience is going to evaluate the animation.
In order to see the full story, I also conducted a few benchmarks based on what was happening visually. To do so, I took a screencast of the first full iteration of the loop in each technique, and then used a tool called Physmo to plot every movement of the SVG element. I mapped a comparison of any time the rate of change did not advance visually for more than 2 frames. This shows the amount of time that the animation would appear paused, therefore the jank. Here is how each technique stacked up:
As you can see, just as Jack's demonstration showed, optimized CSS did not actually outperform every other technique in terms of visual display. SMIL had the most consistent rate of change, then GSAP followed. GSAP, CSS, and Velocity performed in a relatively similar range compared to what the timeline reported, which was that they were far different.
Please keep in mind that the screencast technology could feasibly alter the results here. I encourage you to play with the demos I made or, better yet, write your own comparisons to see how the techniques stack up.
Benchmarks vary depending on the context. Working with a different set of parameters, especially while loading other resources could affect these results. An ongoing dialog surrounding performance under different circumstances is vital for improving technologies in animation.
More Complex Animations
This is all well and good for short animations, but what is it like building a longer, more complex animation? GSAP allows you to work in an adjustable timeline, or many timelines — all of which you can adjust the timescale of, change placement in order, and even overlap. CSS does not allow you to overlap different transforms at once, which, for very realistic motion, ends up being a big deal. If you think about how someone moves, or how objects interact with each other, there are very rarely events when everything works in one linear chain without overlap.
In CSS animation you can chain events with delays, but what happens when you want to adjust one part of it, and it has corresponding parts? You then have to retrace your steps through the whole process of building and redo the math for everything that follows. GSAP's timeline gives you much more control for manipulating these. They also allow for things like physics, which can be instrumental for realistic animation.
SMIL is great for things like a morphing SVG, which none of the other techniques offer at the same capacity. However, it is yet unclear whether the spec will be maintained over time, and because you have to use existing points, it makes less sense to use this technique for many disparate elements at a time.
CSS is wonderful for things like transitions of page elements. Things you see more often on a corporate website where the goal is not to show off animation, but rather smaller effects to add interest or emphasize changes. If you need a tiny bit of interaction, hover effects and lightweight scrolling libraries such as Waypoints can be an easy way to do so.
Animation libraries like GSAP and Velocity are great to use in production because the upkeep and the amount of code necessary is much smaller. Velocity might not perform as well as the others, but the simple fact that you can change your existing jQuery code to something more performant with one word is a huge boon. Velocity also offers physics, which CSS does not. GSAP takes it all one step further: you can take existing jQuery and simply add the GSAP jQuery plugin. It will override your existing jQuery and make it all perform more efficiently without you having to change any code. GSAP also has physics, motion along a path, you name it.
Because of some serious performance failings, jQuery on it's own should no longer be considered an appropriate way of animating things.
Recommendations for use:
- Use CSS animations for small transitions or simple animations. You need not load another resource, and small transforms on hover can be a boon for interaction and UX. Particularly when you don't need physics or to do a lot of stacking SVG transforms, which are not always necessary.
- Use SMIL for morphing SVGs into one another in the case of logos, etc., and when the thing being animated can fallback to a stagnant image in IE.
- Use Velocity for a performance boost on existing jQuery animations without having to change a lot of code.
- Use GSAP for highly performant animations or longer-scale animations that have multiple scenes. It solves major issues with browser-to-browser consistency for SVG transform origin. GSAP is very robust with a broad feature-set, but you can use smaller versions without a lot of bells and whistles, loading only what is necessary.
Everyone has their own preferences, and it is impossible to be completely unbiased. It's important to be purposeful in our selection of tools, as they all have specific tradeoffs, and context matters within a development environment. This post serves as a general comparison to help point developers to the most appropriate technique for what they are setting out to accomplish.