Jump to content

Animating SVG with GSAP

| GreenSock

Note: This page was created for GSAP version 2. We have since released GSAP 3 with many improvements. While it is backward compatible with most GSAP 2 features, some parts may need to be updated to work properly. Please see the GSAP 3 release notes for details.

When it comes to animation, SVG and GSAP go together like peanut butter and jelly. Chocolate and strawberries. Bacon and...anything. SVG offers the sweet taste of tiny file size plus excellent browser support and the ability to scale graphics infinitely without degradation. They're perfect for building a rich, responsive UI (which includes animation, of course).

However, just because every major browser offers excellent support for displaying SVG graphics doesn't mean that animating them is easy or consistent. Each browser has its own quirks and implementations of the SVG spec, causing quite a few challenges for animators. For example, some browsers don't support CSS animations on SVG elements. Some don't recognize CSS transforms (rotation, scale, etc.), and implementation of transform-origin is a mess. Don't worry; GSAP smooths out the rough spots and harmonizes behavior across browsers for you. There are quite a few unique features that GSAP offers specifically for SVG animators. Below is a list of common challenges along with GSAP solutions. This page is intended to be a go-to resource for anyone animating SVG with GSAP. Before moving on, make sure you download the latest GSAP.

Challenge: scale, rotate, skew, and move using 2D transforms

No problem. 2D transforms work exactly like they do on any other DOM element.

TweenLite.to("#gear", 1, {x:100, y:100, scale:0.5, rotation:180, skewX:45});
  • IE and Opera don't honor CSS transforms at all, so GSAP applies these values via the SVG transform attribute like:
    <g id="gear" transform="matrix(0.5, 0, 0, 0.5, 100, 0)">...</g>
    When it comes to animating or even setting 2D transforms in IE, CSS simply is not an option.
    #gear {
      /* won't work in IE */
      transform: translateX(100px) scale(0.5);
    Very few JavaScript libraries take this into account, but GSAP handles this for you behind the scenes so you can get amazing results in IE with no extra hassles.

Challenge: set the transformOrigin (the point around which rotation and scaling occur)

Another unique GSAP feature: use the same syntax you would with normal DOM elements and get the same behavior. For example, to rotate an SVG <rect> that is 100px tall by 100px wide around its center you can do any of the following:

TweenLite.to("rect", 1, {rotation:360, transformOrigin:"50% 50%"}); //percents
TweenLite.to("rect", 1, {rotation:360, transformOrigin:"center center"}); //keywords
TweenLite.to("rect", 1, {rotation:360, transformOrigin:"50px 50px"}); //pixels

The demo below shows complete parity between DOM and SVG when setting transformOrigin to various values. We encourage you to test it in all major browsers and devices.

See the Pen SVG + CSS Transform Timeline by GreenSock (@GreenSock) on CodePen.

  • More Details
    According to the SVG spec, the transform origin of an element is relative to its parent SVG canvas. So if you want to rotate an SVG child element around its own center, you need to manually plot that point in relation to the top-left corner of the SVG canvas. This can be rather cumbersome with multiple elements or if you ever change the position of the element. In contrast, a DOM element's transform-origin is relative to its own top left corner. Most developers expect (and most likely appreciate) the behavior they are accustomed to in the DOM – transform-origin is relative to the element itself. Among other transform-origin related browser bugs (like zooming in Safari) we also found that FireFox doesn't honor percentages or keyword-based values. To learn the technical details of how GSAP fixes these transformOrigin issues behind the scenes, check out https://css-tricks.com/svg-animation-on-css-transforms/

Challenge: set transformOrigin without unsightly jumps

You can run into some unexpected (yet "according to spec") results when changing the transformOrigin after an element has been transformed. In simple terms, once you scale or rotate an SVG element and then change its transformOrigin, the new transformOrigin is aligned to where it would have been according to the elements un-transformed state. This forces the element to be re-positioned and then the transforms are applied – leading to some awkward results. With smoothOrigin enabled CSSPlugin applies some offsets so that the transformOrigin will be placed where you want without any jumps. It's a tough concept to explain with mere words so we made a nice little video for you and an interactive demo.

Study the demo below and scrub slowly.

See the Pen smoothOrigin demo by GreenSock (@GreenSock) on CodePen.

  • More Details
    As of version 1.17.0 when changing the transformOrigin (or svgOrigin) of an SVG element, CSSPlugin will automatically record/apply some offsets to ensure that the element doesn't "jump". You can disable this by setting CSSPlugin.defaultSmoothOrigin = false, or you can control it on a per-tween basis using smoothOrigin:true | false. As of the release of 1.17.0 smoothOrigin only applies to SVG elements. If you would like to see this behavior applied to normal DOM elements, let us know in the comments below.

Challenge: transform SVG elements around any point in the SVG canvas

Sometimes it's useful to define the transformOrigin in the SVG's global coordinate space rather than relative to the element itself. GSAP has you covered. Our CSSPlugin recognizes a svgOrigin special property that works exactly like transformOrigin but it uses the SVG's global coordinate space instead of the element's local coordinate space. This can be very useful if, for example, you want to make a bunch of SVG elements rotate around a common point.

//rotate svgElement as though its origin is at x:250, y:100 in the SVG canvas's global coordinates.
TweenLite.to(svgElement, 1, {rotation:270, svgOrigin:"250 100"}); 

The demo below shows how transformOrigin and svgOrigin compare.

See the Pen svgOrigin demo: SVG tips article by GreenSock (@GreenSock) on CodePen.

  • More Details
    For the majority of use cases where setting a point of origin is necessary, transformOrigin is ideal, as it delivers behavior consistent with normal DOM elements in all major browsers. No headaches. However, there will be times when svgOrigin will come in handy too. Sara Soueidan used this feature in her excellent Circulus tool demo. svgOrigin only supports px-based values (no percentages).

Challenge: animate SVG attributes like cx, cy, radius, width, etc.

CSSPlugin handles pretty much any CSS properties like fill, stroke, strokeWeight, fillOpacity, etc. but to animate attributes you can use AttrPlugin which handles any numeric attribute. For example, let's say your SVG element looks like this:

[code lang="html"]

You could tween the "x", "y", "width", or "height" attributes using AttrPlugin like this:

TweenLite.to("#rect", 1, {attr:{x:100, y:50, width:100, height:100}, ease:Linear.easeNone});

Don't forget to load the AttrPlugin (it's already included inside TweenMax). Check out the JS tab in the demo below to see the syntax used for CSSPlugin and AttrPlugin.

See the Pen SVG CSSPlugin and AttrPlugin by GreenSock (@GreenSock) on CodePen.

  • More Details
    If you want to specify a particular unit (px or percentages) in your AttrPlugin tween it is important that the element already use the same units. AttrPlugin doesn't do unit conversion (like between % and px).
    //Given the following element with percentage-based position:
    //The following tween would put the top left corner of the  exactly in the center of its parent's coordinate space.
    TweenLite.to("#rectangle", 1, {attr:{x:"50%", y:"50%"});
    By combining percentage-based positional attributes and percentage-based transforms you could center the <rect> in its parent like so:
    TweenLite.to("#rectangle", 1, {attr:{x:"50%", y:"50%"}, x:"-50%", y:"-50%"})
    See the demo.

Challenge: use percentage-based x/y transforms

Another "gotcha" in the world of SVG is that percentage-based transforms are not accounted for in the SVG spec. When building responsive sites it can be very handy to move or simply position an element based on a percentage of its own native width or height. In the demo below four boxes of varying widths are all translated along the x-axis based on 100% of their width. No need to manually plug in unique pixel values for unique tweens of each element. All the animation runs off 1 line of code (see js tab).

See the Pen SVG Percent-based translation by GreenSock (@GreenSock) on CodePen.

  • More Details
    To make this happen GSAP converts the percentage values you provide to pixel values. There is one important caveat: the value are not “live” like normal percentage-based CSS transforms are. GSAP has to do the math to bake the pixel values into the matrix(), thus if you change the element’s width or height AFTER you apply a GSAP percentage-based transform, the translation won’t be adjusted.

Challenge: drag SVG elements (with accurate bounds and hit-testing)

There are quite a few tools out there that allow you to drag DOM elements, but few are optimized for SVG elements. With GreenSock's Draggable, you can drag and drop SVG elements, confine movement to any axis and/or within bounds, do hitTest() detection, and throw or spin them too (with ThrowPropsPlugin). Impressive fact: it even works inside nested transformed elements. Each interactive element below is a <g> contained in a single SVG canvas.

See the Pen SVG Draggable by GreenSock (@GreenSock) on CodePen.

Challenge: animate SVG strokes

DrawSVGPlugin allows you to progressively reveal (or hide) the stroke of an SVG <path>, <line>, <polyline>, <polygon>, <rect>, or <ellipse>. It does this by controlling the stroke-dashoffset and stroke-dasharray CSS properties. You can even animate the stroke in both directions.

See the Pen DrawSVGPlugin Animation by GreenSock (@GreenSock) on CodePen.

  • More Details
    Unlike most "pure CSS" solutions that only allow you to animate what percentage of a stroke is visible, DrawSVGPlugin allows you to animate both the starting and ending positions of the stroke segment that is being animated. This allows you to make more advanced animations:
    • Increase/reveal stroke segment from beginning, end, center or any position.
    • Decreease/hide stroke segment to beginning, end, center or any position.
    • Move a segment of a stroke along a path for that snake in a maze effect.

See the Pen SVG Tips: DrawSVGPlugin Values by GreenSock (@GreenSock) on CodePen.

DrawSVGPlugin is a bonus plugin for Club GreenSock members.

Challenge: morph SVG paths with differing numbers of points

MorphSVGPlugin provides advanced control over tweens that morph SVG paths.

See the Pen MorphSVG - sequence by GreenSock (@GreenSock) on CodePen.

  • More Details
    • Morph <path> data even if the number (and type) of points is completely different between the start and end shapes! Most other SVG shape morphing tools require that the number of points matches.
    • Morph a <polyline> or <polygon> to a different set of points
    • There's a utility function, MorphSVGPlugin.convertToPath() that can convert primitive shapes like <circle>, <rect>, <ellipse>, <polygon>, <polyline>, and <line> directly into the equivalent <path> that looks identical to the original and is swapped right into the DOM.
    • Optionally define a "shapeIndex" that controls how the points get mapped. This affects what the inbetween state looks like during animation.
    • Instead of passing in raw path data as text, you can simply feed in selector text or an element and the plugin will grab the data it needs from there, making workflow easier.

MorphSVGPlugin is a bonus plugin for Club GreenSock members (Shockingly Green and Business Green).

Other SVG Gotchas

GSAP does a lot to remove the hurdles of animating with SVG, but there are still a few things to keep in mind:

  • The current SVG spec does not account for 3D transforms. Browser support is varied. Best to test thoroughly and have fallbacks in place.
  • There are quite a few browser bugs related to CSS transforms on SVG elements, some of which can interfere with GSAP's ability to animate things properly so we'd strongly recommend only using GSAP to apply transform-related properties like scale, rotation, x, y, etc.
  1. In Chrome (at least as of June 2015), getComputedStyle() returns the WRONG transform values on SVG elements. It doesn't recognize any non-identity values. So, for example, if you apply a class to an SVG element and it has transform: scale(0), Chrome will say its computed scale is 1. Doh! The same goes for any transforms - if you rotate or move or whatever in CSS, Chrome reports it as scale:1, rotation:0, translate:0, etc. So when GSAP asks the browser for the current value, it'll get bogus data.
  2. In Firefox, if you apply a CSS transform to an SVG element, it overrides any transform that is applied via the transform attribute. So if you inspect the element in Dev Tools, you'll see that GSAP is animating the values perfectly in the SVG's transform attribute, but visually you'll see no changes because the CSS class defines something like transform: scale(0) which takes precedence over the transform attribute. As far as we know, there's no way for GSAP to work around this, so it's best to just avoid defining transforms via CSS and use GSAP directly, like TweenLite.set(..., {scale:2, rotation:30, ...})
  • Most browsers don't GPU-accelerate SVG elements. GSAP can't change that.
  • SVG is lightweight and resolution-independent, but that also can be costly when it comes to performance because rather than just shoving rasterized pixels around (which GPUs are really good at), browsers have to calculate the geometry/paths on each frame. Flash developers will remember converting vectors to bitmaps using cacheAsBitmap. In Flash Player this led to considerable performance gains. Will be interesting to see if browsers offer developers a similar option.

Browser support

All SVG features in this article will work in IE9+ (IE8 doesn't support SVG) and all other major desktop and mobile browsers unless otherwise noted. If you find any cross-browser inconsistencies please don't hesitate to let us know in our support forums.


blog-svg-tips-full The SVG Animations collection above is just a small sampling of Chris' work. Be sure to also check out Chris Gannon's full portfolio on CodePen and follow him on Twitter for a steady influx of inspiration.

Awesome SVG Resources

Get Started Quickly with GSAP

Below are a few resources that will get you up and running in no time:

Get an all-access pass to premium plugins, offers, and more!

Join the Club

User Feedback

Recommended Comments

Awesome, thanks ! smoothOrigin for normal DOM elements please ! ! ! :) Meanwhile have you a trick to avoid jump for normal DOM elements ?
Link to comment
Share on other sites

@daweed31, we may add smoothOrigin for "normal" DOM elements at some point, but we wanted to gauge the interest level of our user base first and see how well-received the SVG-specific feature was. If others want smoothOrigin for normal DOM elements, please let us know. The more requests we get, the more likely we'll add it but there are some complexities we'll have to overcome if we go down that path.
Link to comment
Share on other sites

Thats great, thanks for posting the SVG Resources :-) Theres are also SVG optimisers out there that reduce trailing floats and extraneous metadata.
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now