en en en en en en en en en en en en en en en en en en fa en en fr en hbs_lat en en es en en en ms en de en fr en en en ca en en en en en en en en en en en en ro en en de si ms en en en en en en en en en en en en en en en en en en en en en en en ko en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en fr en en en eu en en en en en fi en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en hu en en hbs_lat en en war en hbs_lat en en hbs_lat en en en en en en en en en en en en en en en en en en en en en it en fr en es en fr en en en de en en en en en es en en en en en en en fr cv es tr es en en en en ms en en en en en en fr en hbs_lat en en en en en en en fr cv es tr es en en en en de en en en ca en en en en en
Nesting ScrollTriggers inside multiple timeline tweens
A very common mistake is applying ScrollTrigger to multiple tweens that are nested inside a timeline. Logic-wise, that can't work. When you nest an animation in a timeline, that means the playhead of the parent timeline is what controls the playhead of the child animations (they all must be synchronized otherwise it wouldn't make any sense). When you add a ScrollTrigger with scrub, you're basically saying "I want the playhead of this animation to be controlled by the scrollbar position"...you can't have both. For example, what if the parent timeline is playing forward but the user also is scrolling backwards? See the problem? It can't go forward and backward at the same time, and you wouldn't want the playhead to get out of sync with the parent timeline's. Or what if the parent timeline is paused but the user is scrolling?
So definitely avoid putting ScrollTriggers on nested animations. Instead, either keep those tweens independent (don't nest them in a timeline) -OR- just apply a single ScrollTrigger to the parent timeline itself to hook the entire animation as a whole to the scroll position.
If you want to animate the same properties of the same element in multiple ScrollTriggers, it’s common to create logic issues like this:
gsap.to('h1', { x: 100, scrollTrigger: { trigger: 'h1', start: 'top bottom', end: 'center center', scrub: true } }); gsap.to('h1', { x: 200, scrollTrigger: { trigger: 'h1', start: 'center center', end: 'bottom top', scrub: true } });
Did you catch the mistake? You might think that it will animate the x value to 100 and then directly to 200 when the second ScrollTrigger starts. However if you scroll through the page you’ll see that it animates to 100 then jumps back to 0 (the starting x value) then animates to 200. This is because the starting values of ScrollTriggers are cached when the ScrollTrigger is created.
See the Pen ScrollTrigger to() logic issue by GreenSock (@GreenSock) on CodePen.
To work around this either use set immediateRender: false (like this demo shows) or use .fromTo()s for the later tweens (like this demo shows) or set a ScrollTrigger on a timeline and put the tweens in that timelines instead (like this demo shows).
Using one ScrollTrigger or animation for multiple "sections"
See the Pen ScrollTrigger generic target issue by GreenSock (@GreenSock) on CodePen.
Since each of the elements would get triggered at a different scroll position, and of course their animations would be distinct, just do a simple loop instead, like this:
See the Pen ScrollTrigger generic target issue - fixed with scoping by GreenSock (@GreenSock) on CodePen.
Additionally, if you want the animation values to update, make sure the ones you want to update are function-based values and set invalidateOnRefresh: true in the ScrollTrigger.
Start animation mid-viewport, but reset it offscreen
For example try scrolling down then back up in this demo:
See the Pen ScrollTrigger reset issue by GreenSock (@GreenSock) on CodePen.
Notice that we want the animation to start mid-screen, but when scrolling backwards we want it to reset at a completely different place (when the element goes offscreen). The solution is to use two ScrollTriggers - one for the playing and one for the resetting once the element is off screen.
See the Pen ScrollTrigger reset issue - fixed with two ScrollTriggers by GreenSock (@GreenSock) on CodePen.
Creating ScrollTriggers out of order
If you have any ScrollTriggers that pin elements (with the default pinSpacing: true) then the order in which the ScrollTriggers are created is important. This is because any ScrollTriggers after the ScrollTrigger with pinning need to compensate for the extra distance that the pinning adds. You can see an example of how this sort of thing might happen in the pen below. Notice that the third box's animation runs before it's actually in the viewport.
See the Pen ScrollTrigger creation order issue by GreenSock (@GreenSock) on CodePen.
To fix this you can either create the ScrollTriggers in the order in which they are reached when scrolling or use ScrollTrigger's refreshPriority property to tell certain ScrollTriggers to calculate their positions sooner (the higher the refreshPriority the sooner the positions will be calculated). The demo below creates the ScrollTriggers in their proper order.
See the Pen ScrollTrigger creation order issue - fixed by GreenSock (@GreenSock) on CodePen.
Loading new content but not refreshing
All ScrollTriggers get setup as soon as it's reasonably safe to do so, usually once all content is loaded. However if you're loading images that don't have a width or height attribute correctly set or you are loading content dynamically (via AJAX/fetch/etc.) and that content affects the layout of the page you usually need to refresh ScrollTrigger so it updates the positions of the ScrollTriggers. You can do that easily by calling ScrollTrigger.refresh() in the callback for your method that is loading the image or new content.
Why does my "scrub" animation jump on initial load? Or my non-scrub animation start playing?
Most likely the ScrollTrigger’s start value is before the starting scroll position. This usually happens when the start is something like "top bottom" (the default start value) and the element is at the very top of the page. If you don’t want this to happen simply adjust the start value to one that’s after a scroll position of 0.
Tip: How to make "scrub" animations take longer
The duration of a "scrub" animation will always be forced to fit exactly between the start and end of the ScrollTrigger position, so increasing the duration value won't do anything if the start and end of the ScrollTrigger stay the same. To make the animation longer, just push the end value down further. For example, instead of end: "+=300", make it "+=600" and the animation will take twice as long.
If you want to add blank space between parts of a scrubbed animation, just use empty tweens as the docs cover.
Navigating back to a page causes ScrollTrigger to break
If you have a single-page application (SPA; i.e. a framework such as React or Vue, a page-transition library like Highway.js, Swup, or Barba.js, or something similar) and you use ScrollTrigger you might run into some issues when you navigate back to a page that you've visited already. Usually this is because SPAs don't automatically destroy and re-create your ScrollTriggers so you need to do that yourself when navigating between pages or components.
To do that, you should kill off any relevant ScrollTriggers in whatever tool you're using's unmount or equivalent callback. Then make sure to re-create any necessary ScrollTriggers in the new component/page's mount or equivalent callback. In some cases when the targets and such still exist but the measurements are incorrect you might just need to call ScrollTrigger.refresh(). If you need help in your particular situation, please make a minimal demo and then create a new thread in our forums along with the demo and an explanation of what's going wrong.
Still need some help?
The GreenSock forums are the best place to get your questions answered. We love helping people develop their animation superpowers.
Get an all-access pass to premium plugins, offers, and more!
Jams | Basic Agency
View All Submit a Showcase
Cook up some delightful animation today with a generous dose of GSAP.
Sign in to follow this   Followers 6
Go to blog posts
Blizzart 0 Likes (Newbie)
Posted March 26 (edited)
Nesting ScrollTriggers inside multiple timeline tweens
Better to see once example
"applying ScrollTrigger to multiple tweens that are nested inside a timeline"
Is it not these, for example?
const tl1 = gsap.timeline({})   .to('#jsScn21', 1, {top:'-200vh', ease:Power1.easeInOut}, '-=2.85')   .to('#jsScn22', 1, {top:'-200vh', ease:Power1.easeInOut}, '-=1.85')   .to('#jsScn23', 1, {top:'-200vh', ease:Power1.easeInOut}, '-=1.85')   const scroll1 = ScrollTrigger.create({         trigger: "#jsScene1",       start: "top top",       end: "+=500%",       animation: tl1  });   const tl2 = gsap.timeline()   .fromTo('#jsScn21', 1, {top:'-200vh'}, {top:'-300vh', ease:Power1.easeInOut})   .fromTo('#jsScn22', 1, {top:'-200vh'}, {top:'-300vh', ease:Power1.easeInOut}, '-=.85')   .fromTo('#jsScn23', 1, {top:'-200vh'}, {top:'-300vh', ease:Power1.easeInOut}, '-=.85') const scroll2 = ScrollTrigger.create({ trigger: "#jsScene2", start: "-=200%", end: "+=500%", animation: tl2 });
Edited March 26 by Cassie
Share on other sites
Cassie 4,519 Likes (Superhero)
No, nested would look like this...
A scrollTrigger both on a timeline, and on one or more of the tweens inside the timeline.
const tl1 = gsap.timeline({})   .to('#jsScn23', 1, { top:'-200vh', ease:Power1.easeInOut, scrollTrigger: { trigger: "#something",       start: "top top",       end: "+=500%", } })   const scroll1 = ScrollTrigger.create({         trigger: "#jsScene1",       start: "top top",       end: "+=500%",       animation: tl1  });
Share on other sites
Blizzart 0 Likes (Newbie)
it is the accidental post 🙃
Share on other sites
Blizzart 0 Likes (Newbie)
@Cassie Thank you, for a good example. Now it is clear. I wouldn't do that 😃
But I think this mistake similar this is a function for lotti, which already has its own trigger.
And if it's to do another different animations "#jsScn22",
after each such animation, the previously configured "start" and "end" triggers in ScrollLottie break.
const tl1 = gsap.timeline({})
.to('#jsScn22', 1, {top:'-200vh', ease:Power1.easeInOut}, '-=1.85')
const tl2 = gsap.timeline()
.fromTo('#jsScn22', 1, {top:'-200vh'}, {top:'-300vh', ease:Power1.easeInOut}, '-=.85')
If so, then it is worth mentioning in this paragraph.
Here you can clearly see this:
if uncommented animation in "const tl2 = gsap.timeline({})"
triggers "start" and "end" are shift
Share on other sites
Create an account or sign in to comment
You need to be a member in order to leave a comment
Sign up for a new account in our community. It's easy!
Register a new account
Already have an account? Sign in here.
Most Common ScrollTrigger Mistakes
“The best thing about GSAP is that it just works, and it works well. On every single browser I’ve tested.”
“GSAP should be the default when it comes to Javascript animations. It should literally be part of the next Javascript update.”
“It's shocking the @w3c didn't use @greensock as a model of how to do animation via code. Did they even ask animators what they use?”
“Any time I've struggled to achieve a complex animation in CSS alone, I've never regretted using @greensock 's GSAP. After all these years, and impressive competitors, it's still Best In Class.”
“Honestly think without GSAP, I would have changed careers by now; it's that good.”
“This stuff is so incredibly amazing I can't believe it. The level of details and options put into these things and the natural instinct GreenSock has for solving everyday problems is impressive.”
“Reading through the GreenSock docs; been amazed like 14 times so far! How can a library be SO complete? Been using that for about 2 years now but man... This the first time I feel this way about a library.”
“If every library were as robust and reliable as GreenSock’s, the world would be a much better place for software engineers and their clients. I can't think of a better designed or better performing tool, and as a bonus, it's fun as heck to play with.”
“Go and browse through FWA or Awwwards, then view source of anything you see that has cool animation and you will be surprised how widely GSAP is used.”
Sign Up For Our Newsletter
Get the latest updates on GreenSock products, exclusive offers, and more right in your inbox.
Your information will always be kept confidential.
Thanks for signing up!
Now you'll begin receiving the latest GreenSock updates, exclusive offers, and more right in your inbox. Welcome aboard.