Jump to content

Search In
  • More options...
Find results that contain...
Find results in...
Firmin Martin

ScrollTrigger: between two scenes, snap to the nearest scene

Go to solution Solved by akapowl,

Recommended Posts



I just made my first steps with gsap + ScrollTrigger, but have struggled to snap to the nearest scene when two scenes are visible (see the pen in the end). That's not something unexpected, as I looped over the scenes and assigned them a snap value 1. But all the variants I tried failed (see the snapTo: 1 / (scenes.length - 1) approach:  

See the Pen mdMbadp by firmart (@firmart) on CodePen

 and the snapTo: "labels" approach: 

See the Pen YzxKdgO by firmart (@firmart) on CodePen

).  I'm aware of the given examples

  1. See the Pen YzyaKrq by GreenSock (@GreenSock) on CodePen

  2. See the Pen XWmEoNg by GreenSock (@GreenSock) on CodePen

But the former seems to rely on the CSS properties scroll-snap-typeandscroll-snap-align(I believe that it can be done with gsap alone)  and the latter has a hardcoded width (not sure whether it's relevant).


How can I snap to the nearest scene (upper scene's end or lower scene's beginning) when the scroller is between two scenes ?



See the Pen oNeveJy by firmart (@firmart) on CodePen

Link to comment
Share on other sites

  • Solution

Welcome to the forums @Firmin Martin


I would probably do things a bit different altogether.


For one you don't really need two different forEach-loops, you can create the timelines with scrollTriggers for your containers from within that first forEach-loop you have for the sections by just targetting the sections container element.


For the snapping I would probably juts create one extra ScrollTrigger, that 'spans' across the whole page-scroll.


For the logic of the snapping, think about it this way:


You have two states (starting-state and end-state of the animation of each section) with the duration of the pinning being equal to the duration of the free-scrolling in between sections (i.e. the window's height) so you could just take the number of your scenes, multiply that by 2 (because of the two 'states') and then in the end substract 1 (because snapping to 0 will be added automatically and you have to consider that).


  start: 0,
  end: "max",
  //snap: [0, 0.2, 0.4, 0.6, 0.8, 1]
  snap: 1/(scenes.length * 2 - 1)


That could then look something like this:


See the Pen be907573a8ade3f0eea9076ce04a1083 by akapowl (@akapowl) on CodePen




That works just fine, but with a scenario like this you will run into following issue:


Since you will be snapping to points where the pinning is just about to start/end and after snapping you continue scrolling up or down (depending on where you snapped to) you will be seeing nasty jumps of the pinned container - which is nothing ScrollTrigger can do much about because scrolling and js-processing are handled on two different threads by the browser.


So here is another version including a suggested workaround for that by @GreenSock from this thread



where it just offsets the snapping by a little bit depending on where you snap to. I'm not exactly sure if this is the simplest implementation of that workaround (because I had to also work around how JS is handling small numbers) but it works just about right. I Hope that will help :) Cheers.


See the Pen 42a73ce2154cb620af866c6e3d90a394 by akapowl (@akapowl) on CodePen


  • Like 3
Link to comment
Share on other sites

@akapowl Many thanks for your answer and the workaround for an issue I've not even think about! I have some further questions:

  1.  You used end: "max" in the extra ScrollTrigger, but I didn't find max documented, is that an accepted value ?
  2. The two states thing is due to the .from method + an implicit .to method (which set every property to the default value, e.g. scale: 1) along with pin: true , thus making the height twice as it would be without pin: true , right ?


  • Like 1
Link to comment
Share on other sites


Happy to help :)


1) It really isn't in the docs, didn't know that - I picked it up here in the forums.

And yes, it is an accepted value; you can even see @GreenSock suggesting the use of it in this thread here. 




2) By two "states" I meant

  1.  The position of the container's top meeting up with the window's top edge

  2. The position when the animation/pinning has finished in other words the ScrollTrigger's end  "+=100%" - which is one window-height later.
    So basically you are right with regard to the pinning being responsible for it working like that. The equal heights of the pinSpacing added and the sections themselves are what's making the calculations I used work.


  • Like 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.