Chapter 08 of 11Part 3 · GSAP
The GSAP timeline: sequencing a hero intro
How timelines place tweens in time with the position parameter, labels and defaults, and how to play, reverse and replay them.
8 minBy Zuzo StudioUpdated
In this chapter you will
- place tweens on a timeline with the position parameter and labels
- set shared durations and eases once with timeline defaults
- build your whole hero intro as one timeline you can replay and adjust
Before you startThis builds on A GSAP tutorial: tweens, eases and stagger.
One tween moves one thing. A page intro moves five or six: an eyebrow, the heading words, a line of text, two buttons and a scroll cue, each starting at the right moment relative to the others. You could do that with a delay on every tween, but then changing one duration means recalculating every delay after it. A GSAP timeline solves this. It is a container for tweens that places each one in time relative to the others, and lets you play, pause, reverse or replay the whole sequence as one object. This chapter covers timelines, the position parameter, labels and defaults, then you build your full hero intro as one GSAP timeline.
01Why a GSAP timeline beats a chain of delays
Here is a three step intro written with delays:
gsap.from('.hero-eyebrow', { y: 16, duration: 0.5 });
gsap.from('.hero-title', { y: 24, duration: 0.6, delay: 0.3 });
gsap.from('.hero-lede', { y: 16, duration: 0.5, delay: 0.7 });
It works until you make the eyebrow slower. Then the heading starts too early, and so does everything after it, because each delay was worked out by hand from the durations before it. This is the same problem as chaining CSS animations with delays in CSS keyframes, and it gets worse with every step you add.
The same intro as a timeline:
const tl = gsap.timeline();
tl.from('.hero-eyebrow', { y: 16, duration: 0.5 })
.from('.hero-title', { y: 24, duration: 0.6 }, '-=0.2')
.from('.hero-lede', { y: 16, duration: 0.5 }, '-=0.2');
gsap.timeline() creates the timeline, and its to(), from(), fromTo() and set() methods work exactly like the ones from GSAP basics, except that they add the tween to the timeline instead of starting it on its own. Each method returns the timeline, so you can chain them. By default each new tween is added at the end of the timeline, so the steps run one after another. The '-=0.2' after a tween is the position parameter, which moves it in time. Now each step is placed relative to the one before, and changing one duration moves everything after it automatically.
02The position parameter
The optional last argument of every timeline method says where the tween goes. GSAP's guide to the position parameter lists the forms:
| Position | Means | Use it for |
|---|---|---|
| (none) | At the end of the timeline | Plain one after another |
1 |
Exactly 1 second from the start | Fixed moments, rarely needed |
'+=0.3' |
0.3 seconds after the end of the timeline | A pause between steps |
'-=0.3' |
0.3 seconds before the end of the timeline | Overlapping the previous step |
'<' |
At the start of the previous tween | Two things moving together |
'>' |
At the end of the previous tween | Straight after, even if it is not last |
'<0.1' |
0.1 seconds after the start of the previous tween | A small follow on |
'intro' |
At the label called intro | Named points, see below |
The guide also notes that a number after < or > is relative, so '<0.1' is the same as '<+=0.1', and that you can use percentages of a tween's duration, such as '-=25%'.
Overlap is what makes a sequence feel like one movement instead of a queue. In stagger and sequence we started each step before the previous one ended. On a timeline, '-=0.2' or '<0.1' does exactly that. A good habit is to start with every step at the end, get the order right, then pull steps earlier one at a time until it flows.
03Labels and defaults
Labels
A label is a named point in time. Add one with addLabel(), then place tweens relative to it by name:
tl.addLabel('actions', '-=0.2')
.from('.hero-lede', { y: 16 }, 'actions')
.from('.button', { y: 12, stagger: 0.08 }, 'actions+=0.1');
Both tweens now hang off the actions label. Move the label and both follow. GSAP's Timeline documentation adds that if you use a label that does not exist yet as a position, it is created at the end of the timeline. Labels also make the code readable: six months later, 'actions+=0.1' says more than 1.34.
Defaults
When every tween shares a duration and an ease, set them once. The Timeline documentation explains that anything in a timeline's defaults object is inherited by its child tweens, and that a value set on a tween itself still wins:
const tl = gsap.timeline({ defaults: { duration: 0.6, ease: 'power3.out' } });
tl.from('.hero-eyebrow', { y: 16 })
.from('.scroll-cue', { opacity: 0, duration: 0.4 }); // overrides duration
This is also where the timing choices from your motion brief live: one place to change the feel of the whole intro.
04Controlling a timeline
A timeline is an object you can hold on to and steer. The methods you will use most:
play()andpause(): start or stop where it is.reverse(): run backwards from the current point, which is how a menu closes smoothly even when it was only half open.restart(): jump to the start and play again.seek(time or label): jump to a point without playing through it.progress(0 to 1): read or set how far through it is.timeScale(n): change the speed;0.5is half speed.
Create a timeline with { paused: true } when it should wait for something, such as a click:
const menu = gsap.timeline({ paused: true })
.fromTo('.menu', { autoAlpha: 0, y: -16 }, { autoAlpha: 1, y: 0, duration: 0.3 })
.from('.menu a', { y: 12, stagger: 0.04 }, '<0.1');
toggle.addEventListener('click', () => {
menu.reversed() || menu.progress() === 0 ? menu.play() : menu.reverse();
});
autoAlpha is GSAP's opacity that also sets visibility: hidden at zero, so the closed menu cannot be clicked. The same object opens the menu forwards and closes it backwards, from wherever it is. Doing that with CSS means two separate animations and some care about where each one starts. The getting started guide to timelines walks through more of these controls with live examples.
05Building the hero sequence
Now the full intro. Every step only moves things with transform, except the scroll cue, which is decoration and can fade in from nothing because nobody is waiting to read it. The heading words, the lede and the buttons stay at full opacity throughout, so the heading is still visible on the first paint, as chapter 6 requires.
const intro = gsap.timeline({ defaults: { duration: 0.6, ease: 'power3.out' } });
intro
.from('.hero-eyebrow', { y: '0.5em' })
.from('.hero-title .word', { y: '0.6em', stagger: 0.06 }, '<0.1')
.addLabel('actions', '-=0.3')
.from('.hero-lede', { y: 16 }, 'actions')
.from('.button', { y: 12, stagger: 0.08, clearProps: 'transform' }, 'actions+=0.1')
.from('.scroll-cue', { opacity: 0, duration: 0.4 }, 'actions+=0.4');
Read it top to bottom. The eyebrow rises first. The heading words follow 0.1 seconds after the eyebrow starts, one every 0.06 seconds. The actions label sits 0.3 seconds before the words finish, and the lede, the buttons and the scroll cue all hang off it. With a seven word heading, the whole intro is over in about 1.6 seconds, inside the time budget from chapter 3.
The clearProps: 'transform' on the buttons matters. GSAP animates by writing inline styles, and inline styles beat your stylesheet. Without it, each button would keep an inline transform after the intro, and the hover lift from CSS transitions would stop working. GSAP's CSSPlugin documentation describes clearProps as removing the listed properties from the element's inline style when the tween completes, so your CSS takes over again.
Check your understanding
3 questions
Key takeaways
- A timeline places each tween relative to the others, so changing one duration moves everything after it instead of breaking hand made delays.
- The position parameter overlaps steps with "-=", adds gaps with "+=", and pairs tweens with "<" and ">".
- Labels name points in time, so several tweens can hang off one moment and move together.
- Timeline defaults set the duration and ease once, and any tween can still override them.
- GSAP writes inline styles, so use clearProps when a stylesheet, such as a hover state, needs control back after the tween.
Sources
- TimelineGSAP, checked
- Understanding the position parameterGSAP, checked
- TimelinesGSAP, checked
- CSSPluginGSAP, checked