Skip to main content

3.7 release

· 5 min read
Cassie Evans
Jack Doyle

Percentage based position parameter.

The position parameter is small but mighty. It's the key to building sequenced animations with precise control over timings, and now it's even more powerful!

This update gives us the ability to position animations using percentage values - either relative to the previous tween or animation, or relative to the duration of the animation being inserted. The percent is based on the totalDuration(), so repeats, yoyos and staggers will be factored in.

This is such an exciting one because it allows us to tweak durations without affecting positioning!

Say we wanted to overlap a tween by half of it's own duration. Until now we would do a little mental math, divide the duration in half and add it to the position parameter as a relative position., {duration: 2}, "-=1");

But if we were to change the duration, we would also have to update the position parameter

Now, with the addition of percentages, we can do this instead:

// overlap by half of the inserted tweens duration, -1s:, {duration: 2}, "-=50%");

Alternately, we can position a tween or timeline in relation to the most recently-added animation.".other", {x: 100, duration: 2});
// insert 25% of the way through the most recently added animation.
// In this case - 0.5s into the 2s duration.".class", {x: 100}, "<25%");

Or at a percentage from the end of the most recently-added animation, like ">-25%".

>-25% is equivalent to <75%".other", {x: 100, duration: 2});
// insert 25% of the way from the end of the most recently added animation.
// In this case - 0.5s from the end of the 2s duration.".class", {x: 100}, ">-25%");

As '+=' and '-=' are always based on the inserting animations total duration, we can even use a pointer to reference the starting point of the previous tween, whilst using the inserting tweens duration as the percentage offset.".other", {x: 100, duration: 2});
// insert 50% of the inserting tweens duration from the beginning of the most recently added animation.
// In this case - 0.5s from the start of the previous tween.".class", {x: 100, duration: 1},"<+=50%");

Powerful stuff! If you want to dig in a bit more, here's a video explainer and some demos to play around with. You'll be a positioning pro in no time!

Video Walkthrough

Check it out in action in these demos.



Interactive Position Parameter Demo


Better support for SVG elements with Flip plugin.

Flip plugin has been extended with better support for SVG elements. SVG already has a great coordinate system to work within - but we think this could assist transitions in live data-vis or when animating between states in generative SVG.

We'd love to see what you do with this so don't forget to share your demos with us!

In the meantime, here's a simple example


Easily scope your animations

Modern front end dev is all about encapsulated components, but scoping animations to each individual component can be tricky. React devs, for example, often find themselves in "ref Hell" creating a ref for each and every element they want to animate. Wouldn't it be nice to just use classes and selector text that's limited to your component instance?


With gsap.utils.selector() you can grab descendant elements from the selected element.

This is great for components because you can create a scoped selector for that component's main container element and then use that to select descendants. It's similar to calling .querySelectorAll() on that element rather than on the document except with a few added benefits:

  • It returns an Array rather than a NodeList, so you get access to convenient array methods like .filter() and .map().
  • You can pass a React ref or Angular ElementRef to gsap.utils.selector(). Then when you use the resulting function, it will automatically check for the .current/.nativeElement in case it was re-rendered since creation.
// Vanilla
let q = gsap.utils.selector(myElement); // or use selector text like ".class"
let boxes = q(".box"); // finds only elements with the class "box" that are INSIDE myElement
// or plug directly into animations".circle"), {x: 100});
// React
let el = useRef();
let q = gsap.utils.selector(el);

useEffect(() => {
// uses el.current.querySelectorAll() internally".box"), {x: 100});
}, []);
// Angular
@Component({ ... })
class MyComponent implements OnInit {

constructor(public el: ElementRef) {
this.q = gsap.utils.selector(el);

ngOnInit() {
// uses this.el.nativeElement.querySelectorAll() internally".box"), { x: 100 });

A common pattern in React is to declare a ref for every element you want to animate, but that can make your code very verbose and hard to read.


By using a scoped selector, we only need to use a single ref. Then we can simply select the descendants.



We've also added an optional, second scope parameter to gsap.utils.toArray()

This will find all the descendant elements of myElement with the class of "box":

gsap.utils.toArray(".box", myElement)

And more...


GSAP 3.7 also delivers various bug fixes, so we'd highly recommend installing the latest version today. There are many ways to get GSAP - see the Installation page for all the options (download, NPM, zip, Github, etc.).


Happy tweening!