Jump to content
Search Community

ScrollTrigger - Lock body scrolling regardless of scroll velocity

SeeMax test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

Hi All,

Longtime listener first time caller.


- I am creating a page that locks / prevents scrolling at the mid point of each section of a page.

- When the scrolling locks an animation plays. Upon completion of the animation the page unlocks and the user can scroll again.

- I am using body {overflow:hidden;}  to prevent scrolling. (Doesn't have to be this but I don't think it's related to the issue)

- I am using a forEach loop to create each sectionsTrigger. 



- The page locks at the exact trigger point if the user is scrolling quite slowly.

- If the user scrolls quickly the page does not lock at the right place / the scrollTriggered animation plays at the wrong place.

- The velocity of scroll determines how badly it misses the trigger position.



- I want to lock the page at the exact moment the trigger hits the start target position.

- Regardless of how fast the user moves I want to stop the page at the start target position.

- I am willing to sacrifice some performance to be precise with the lock.



- I've created a minimal Codepen Demo: 

- I've place a fixed red line at the center of the screen to make the screen- center very clear.

- I'm adding a red border to the body when the locking takes place to make it very apparent it is locked.

- The body unlocks after 3 seconds (I didn't want to add complexity by making it wait for a second animation in the demo).


(I'm assuming there's some sort of beneficial debouncing that doesn't jive with what I'm doing but I've been wrong many times before.)

Thanks so much.





See the Pen PoXJjzZ?editors=1111 by SeeMax (@SeeMax) on CodePen

Link to comment
Share on other sites

Hi there @SeeMax,

Is this something that could help?
@GreenSock created a function that locks the window based when an animation is done.
Perhaps you could use this method? This is how it gets triggerd by scrolltrigger using:

 onEnter: self => {
    self.scroll(self.start + 1);
    masterTL.progress() < 1 && scrollObserver.enable();

Hope this helps?


  • Like 3
Link to comment
Share on other sites

@IndM, Thanks so much for sharing that link. Much appreciated.
It feels like observer may hold the key.

The @GreenSock function in the "Solution" pen only appears to work at 100vh with a trigger position of "top top".
I've forked the pen, changed the div heights to 50vh, and changed the trigger position to "bottom center".

You can see that you are able to scroll past the trigger point if you use enough velocity (and the animation also jumps on completion):

See the Pen bGOYrvK by SeeMax (@SeeMax) on CodePen


Ultimately I just need the animation to play once on scroll up so I simplified things much further.

I created a pen that doesn't utilize pinning or the end value.

The key is indeed the code quoted in the original reply.


 onEnter: self => {
   self.scroll(self.start + 1);
   masterTL.progress() < 1 && scrollObserver.enable();


That locks the screen on trigger perfectly and then the timeline onComplete fires scrollObserver.disable(); to allow scrolling again:

See the Pen zYyPEVP by SeeMax (@SeeMax) on CodePen


I wanted to write all that out in case someone comes upon this and finds the explanation useful for their needs.

But really it's a long winded way of saying: Thank you so much @IndM, you were spot on.


The GSAP forums always come through.





  • Like 4
Link to comment
Share on other sites

Hi All,

I've begun implementing this in a looped setting and I've run in to a new issue (lost the locking again!).
I've created a forEach() loop for each <section> (it was just a single section in the prior example)


When scrolling slowly, and each <section> is reached, the Observer pauses the scroll and plays a section-specific animation in that section (I changed to h2 color animation for easier visualization).


However, if you scroll quickly you can bypass the first sections and get all the way to the last one.

It does lock on the last section but the skipping defeats the purpose.


So I've now lost the scroll locking I was seeking!


Codepen for demonstration:

See the Pen KKbyQRp by SeeMax (@SeeMax) on CodePen


I tried creating a single, unique function for each section (without the loop, with unique var names, etc. but it still failed the test).
I thought maybe it was fastScrollEnd but setting that to false doesn't solve it.

I feel like there is an issue with the observer in the loop or something similar but I'm not able to sus out the exact issue.


Any further assistance would be greatly appreciated.



Link to comment
Share on other sites

  • Solution

That's because it you wheel strongly enough, the native scroll could jump so far that it actually spans across MULTIPLE sections (like if each section is 100px high, and the wheel event's deltaY is 300 for example). So you just need to build in logic for cases like that: 

See the Pen eYbyWbd?editors=0010 by GreenSock (@GreenSock) on CodePen



Link to comment
Share on other sites

Oh, I see. Well, honestly I'm on the fence about that because as a user, I absolutely HATE when websites lock the scroll like that. I can see the scrollbar and I know there's more content to get to...but I'm forcibly prevented from getting to it. Very confusing. Makes me wonder if the browser froze or there's a problem with my device. So adding a helper function like that to the official docs makes me feel a little gross, like I'm actively helping more people do that. 


I'll ponder it. Especially if more people ask for it, perhaps I should get over my personal issue with it. 😬

  • Like 1
  • Haha 2
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...