GSAP Basics: Dive into Web Animations

Jean-Baptiste Kaiser
Jean-Baptiste KaiserMarch 27, 2024
#css#js

Landing pages often have moving pictures to make them more interesting. But making these movements with just HTML and CSS can be hard, so we use special JavaScript libraries for animation.

For our react-admin product's landing page, we chose to use GSAP. We learned a lot about both the GSAP library and animations in general during this process, and we also encountered some tricky parts.

So, we decided to share what we learned in a series of articles:

  1. GSAP Basics: Dive Into Web Animations (this post)
  2. Trigger Animations On Scroll With GSAP
  3. GSAP in practice: some pitfalls to avoid

Let's get started with a quick overview of GSAP.

What is GSAP?

GSAP (for GreenSock Animation Platform) is a JavaScript library that allows to animate elements in a webpage. It makes it possible to create complex and performant animations, while yet offering a very friendly and versatile API.

It also comes with a variety of plugins, some of which are paid, offering powerful and customizable tools to help animate almost anything, from text to SVG, and even include some effects based on physics.

Just have a look at their homepage to get a glimpse of what this library can do, it's amazing!

Now that you are, hopefully, hyped up just like I am, let's dive in!

Main Concepts

In this section, I'll cover two of the most basic concepts introduced by the library.

Tween

Probably the first concept you will come across when reading the GSAP docs are tweens. The term tween comes from the word between, as a tween is an object describing an animation between a from state and a to state. It also holds the target (the object to animate), and any other properties describing the animation, like its duration, or the easing function used to calculate mid-animation values.

Timeline

Basically, the timeline answers the following question: how can I trigger my animations in sequence, or relative to one another, without having to calculate all the delays myself? The solution is to use a timeline to group the tweens together, optionally specifying where the tweens should be placed in the timeline with the position parameter. The timeline can then be manipulated (play, pause, seek a specific frame, ...) as a whole without having to manage the playhead for all tweens manually.

                        PLAYHEAD
|--------------timeline-----|-----------|
|--tween1--|                |
           |-----tween2-----|-----------|

Syntax

In this section, I will go through some of the code syntaxes that I found most useful. But be sure to check out the GSAP docs for more features and detailed examples.

gsap.to()

To create a tween, it can be as simple as:

gsap.to(".box", { x: 100 });

This tells GSAP to create a tween, targeting DOM elements matching the CSS selector ".box". The elements will be animated from their current state (hence their current position in our example), to the state { x: 100 }.

Tip: x is a transform shorthand provided by GSAP, equivalent to transform: translateX(100px).

See the Pen gsap.to() by @slax57 on CodePen.

We did not provide a duration, so by default the animation will take 0.5 seconds.

This can be easily changed using the duration special property:

gsap.to(".box", { x: 100, duration: 2 });

Also, our animation will run immediately, as soon as the page's JavaScript is loaded. We can change that using the delay property:

gsap.to(".box", { x: 100, duration: 2, delay: 1 });

We can also change the "feel" of the animation by changing the ease function. By default, the tween will use the "power1.out" function. There are plenty to choose from, and GSAP even offers a tool to better visualize them. To make the animation a little more fun, we can for instance use the "elastic" ease function:

gsap.to(".box", { x: 100, duration: 2, delay: 1, ease: "elastic" });

See the Pen gsap.to() by @slax57 on CodePen.

gsap.from()

The gsap.to() function has a twin (not to be confused with tween! 😁️) function: gsap.from(). It works exactly the same way. The only difference is that, instead of animating from the element's current state to the specified state, it will do the opposite.

The following example will animate elements with CSS class ".box" from x: -100 to x: 0.

gsap.from(".box", { x: -100 });

This can be very useful to create animations that run on page load, or to make new elements appear.

Here is another example with some opacity change, to make the element fade in:

gsap.from(".box", { x: -100, autoAlpha: 0 });

Tip: autoAlpha is another transform shorthand, for both opacity and visibility.

See the Pen gsap.from() by @slax57 on CodePen.

gsap.fromTo()

Now that we've covered the gsap.to() and gsap.from() functions, you can easily guess what the gsap.fromTo() function does. It can be useful in certain cases to specify both a from and a to state, for example, to apply a style as soon as the JavaScript is loaded, and animate from it immediately after.

In the following example, if the animation is enabled, the element will first have its opacity set to 0, and then will progressively reach an opacity of 0.8. It the animation is disabled, the element will keep its opacity of 1.

if (shouldAnimate) {
  gsap.fromTo(".box", { opacity: 0 }, { opacity: 0.8 });
}

gsap.set()

gsap.set() is the last function returning a tween that I'd like to cover. In essence, it's equivalent to calling gsap.to() with a duration of 0: it allows to apply a state immediately to an element. This can be useful to set a property only if a condition is met, or to set the state from which we will be animating later.

gsap.set(".box", { transformOrigin: "center" });
gsap.to(".box", { rotation: 360, repeat: -1, duration: 5, ease: "linear" });

Tip: repeat: -1 makes an animation repeat infinitely.

See the Pen gsap.set() by @slax57 on CodePen.

gsap.timeline()

As the name suggests, gsap.timeline() allows to create a timeline.

In the following example, the ".circle" element will start animate right after the ".logo" completes its animation. This allows to run the animations in sequence.

const tl = gsap.timeline();
tl.from(".logo", { duration: 2.5, opacity: 0, scale: 0.3 }); // Instead of gsap.from()
tl.from(".circle", { duration: 1, opacity: 0, y: 150 }); // Instead of gsap.from()

See the Pen gsap.timeline() by @slax57 on CodePen.

The main advantage of this syntax is that I can now change the duration of the animation of ".logo", and it will automatically keep the animation of ".circle" in sync: it will always run as soon as the ".logo" animation is complete.

Using a timeline also adds a new ability to the to(), from(), fromTo() and set() functions: they now accept an additional parameter, allowing to specify where in the timeline each animation should be inserted.

const tl = gsap.timeline();
tl.from(".logo", { duration: 2.5, opacity: 0, scale: 0.3 });
tl.from(".circle", { duration: 1, opacity: 0, y: 150 }, "+=2"); // Starts this animation 2 seconds past the end of the timeline (creates a gap)

See the Pen gsap.timeline() by @slax57 on CodePen.

This extra parameter is called the position parameter, and accepts many syntaxes to accommodate for all use cases:

  • 3 insert at exactly 3 seconds from the start of the timeline
  • "<" insert at the start of the previous animation
  • ">" insert at the end of the previous animation
  • "<+=3" 3 seconds past the start of the previous animation
  • ">-0.5" 0.5 seconds before the end of the previous animation
  • "-=25%" overlap with the end of the timeline by 25% of the inserting animation's total duration
  • and so on...

This makes it so much easier to decompose a complex animation into small steps and experiment with the timing of each step independently.

Tip: Timelines can also be nested.

gsap.utils.toArray()

This utility method allows to get an array of elements matching a selector.

It can be useful to:

  • Know how many elements there are (for calculations)
  • Attach an animation to the specific element in the array rather than to all elements (useful to select the current element as a trigger for instance)

In the following example, we use this feature to set a different initial rotation angle for each rectangle, and also a different duration, resulting in different rotation speeds:

const svgRectangles = gsap.utils.toArray('#my-svg rect');
svgRectangles.forEach((rect, i) => {
    gsap.set(rect, {
        rotation: i * 15,
        transformOrigin: '50% 50%',
    });
    gsap.to(rect, {
        rotation: 360 + i * 15,
        duration: 100 - i * 20,
        repeat: -1,
        ease: 'linear',
    });
});

See the Pen gsap.utils.toArray() by @slax57 on CodePen.

Conclusion

This covers some of the basics of GSAP. With this knowledge, you should already have enough to start creating your own animations.

I'm overall pretty impressed with GSAP. In particular, I like its API, which is very versatile, allowing for a very synthetic syntax for the most common use cases, while yet allowing for advanced customization for the most complex ones.

In the next post of this series, we will push complexity a little further, by creating animations that trigger on page scroll.

Did you like this article? Share it!