Jump to content
Search Community

Dynamic ScrollTrigger with pin inside a ScrollSmoother

Ivan Dudinov test
Moderator Tag

Go to solution Solved by Rodrigo,

Recommended Posts

Hi there!

I think I've found a bug for a [possibly pretty rare] case with the following setup:

  1. page consists of pre-defined fixed height sections.
  2. each section has a ScrollTrigger (1) which just watches if a section becomes visible on the screen.
  3. each ScrollTrigger (1) may create an additional ScrollTrigger (2) which uses pinned container.
    1. for the case, it doesn't matter what else happens along with creating an instance of (2), but originally there's a complex setup of various stuff so it makes sense to mount/unmount extra content and logic according to triggering (1).
  4. all the page is wrapped into a ScrollSmoother.


Actual result is that at the moment a dynamic ScrollTrigger (2) is created, smoothed scroll 'jumps' a bit towards scroll direction; the size of the jump depends on scroll speed. Also I've confirmed that it's not a performance lag.


Removing whether a ScrollSmoother or a pin in (2) fixes the issue.


Would love to hear some ideas/hints on how this can be fixed, although I'm also currently thinking about a workaround where I would pre-create pinned containers and try to setup nested ScrollTriggers based on them...


Thank you!  


See the Pen dyQRJLN by idudinov (@idudinov) on CodePen

Link to comment
Share on other sites

  • Solution

Hi @Ivan Dudinov and welcome to the GreenSock forums!


I'm not 100% completely sure of what could be happening here, but most likely this looks like ScrollSmoother updating after the ScrollTrigger instance is being created, which alters the height of the content and that messes up with the way the ScrollSmoother instance is working behind the scenes.


It could be somehow related to what Jack described in this thread:


But is most definitely not the same scenario, that's why I'm not completely sure that my description of the issue is 100% accurate.


This seems to be working as you expect:

See the Pen gOQRzwg by GreenSock (@GreenSock) on CodePen


Hopefully this helps.

Happy Tweening!

Link to comment
Share on other sites

Hi @Rodrigo!

Thank you for the fast reply and the workaround!

It actually helped, however I went further and tried to test it in different real-world scenarios, so had a chance to make it a bit more bullet-proof. 


Here's the updated version with the fix:

See the Pen VwVWOry by idudinov (@idudinov) on CodePen


And sharing the steps I've came up with based on my experience.


Just after the dynamic ScrollTrigger with a pin has been created, do the following:

  1. call ScrollTrigger.refresh()- it's required if the new ST has scrub animation, otherwise its 'start'/'end' might be undefined;
  2. next it's needed to calculate where the page current scroll should actually be at this moment. For my case, I rely on the parent ST – taking its trigger and start/end configuration
    1. determine where from you're approaching the ST – whether 'start' or 'end'. I decided to check current ST's progress like that: progress < 0.5 ? 'start' : 'end'. such approach makes sense when scroll position can be reset by navigation, like we're teleporting from the lowest section to the top of the first one – in this case we'll receive 'onEnterBack' from ST, however visually we're at the top.
    2. then take parent's ST 'start' or 'end' configuration according to previous step, not in pixels but as string like 'bottom top', we name it targetPosition
    3. use it to calculate actual offset via currentScrollSmoother.offset(parentScrollTrigger.trigger, targetPosition) – that gives you final scroll position you need
    4. it's important to add some extra offset (1 or 2 px is enough) to the targetPosition towards the direction (+ or -) to make sure your parent and nested trigger will remain in the trigger area.
  3. set the scroll position instantly via currentScrollSmoother.scrollTop()
  4. and finally refresh your smoother like that: currentScrollSmoother.scrollTrigger.refresh()
  5. Important to make sure that the smoother is currently not being affected by some another scrollTops etc.

I was testing all this on Mac in Chrome, Safari and Firefox. I'll try to keep this thread up to date if I find something some other interesting details.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

After some time of testing everything with real setup, I strongly encourage everyone avoiding creating ScrollTriggers on the fly during page scroll :D 

The main issue with that is even one would do the best to sync scroll position after content is being changed, you'd never align it with async scrolling in Safari (and iOS) browser which makes scrolling thread to has higher priority than rendering.


For some reason, normalizeScroll: true made it worse :( the scroll experience becomes too clunky for me.


Didn't want to sound too dramatic though, so please read it just as a conclusion for a particular context.


Wish all good luck with tweening :) 

  • Like 1
Link to comment
Share on other sites

  • 3 months later...

This was helpful in revealing a change that was necessary in ScrollSmoother to accommodate a situation like this where you're dynamically adding a ScrollTrigger WHILE the smoothing animation is in-progress. The next version of ScrollSmoother should handle this better (you may need to clear your cache): 



Is that what you were looking for?


Thanks for the excellent minimal demo, @Ivan Dudinov 👏

  • Like 1
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
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...