Jump to content
Search Community

ScrollTrigger Does Not Pin When Setting Start Parameter

Steve Giorgi test
Moderator Tag

Recommended Posts

I would love to make a demo for this and will see if I can later today but it's difficult since I'm utilizing React.  I was hoping there was a simple solution:

 

I have several full height containers which are sections of a page.  These are all fixed position so that I can "scroll" through each without actually having the appearance of scrolling while transitioning through each timeline.  I have a "master" timeline in each component (section) which pins to the screen.

 

Obviously, the timeline in my second section is going to start when my first timeline starts since the containers are both positioned at the top of the screen (fixed) and positioned behind one another with z-index.  I understand that I need to calculate an offset and start the second timeline when I have scrolled through the first timeline.

 

Problem is when I set a time such as 1500, it correctly goes through the first timeline and sticks the second to the screen for just a moment.  Scrolling any further completely removes the component from view.  If I scroll back up I see some of the scrubbed animation playing backwards (it is in fact scrubbing forward but removed from view).

 

If I set a position start time such as "bottom bottom" everything works beautifully but obviously my second timeline starts at the same time as my first and by the time I've reached it, I'm half way through the timeline.

 

 

 

I'll try to recreate on Codepen ---- but maybe I'm just missing something.  I'm using these parameters:

 

 

const EnergyTransitionTimeline = new TimelineMax({
      scrollTrigger: {
        trigger: EnergyTransition.current,
        pin: true,
        scrub: 2,
        start: 1500,
        end: "+=" + window.innerHeight * 5,
        markers: true,
        onUpdate: getDirection,
      },
    })

 

Update: pinReparent: true resolves the issue, but this looks extremely expensive and it makes the viewport jump slightly just before the animation begins.  What would I need to setup differently and why would a start time change this behavior?

 

I can also remove pinReparent and offset the start time of my second timeline and it then correctly pins and starts correctly --- this is a viable solution since I then simply have to calculate and offset each of my timelines but this seems like a really odd solution.

Link to comment
Share on other sites

I'm finding it hard to visualise by reading through this I'm afraid pal.

If you could put together a little codesandbox it would be a big help. Also, you're using an older version of GSAP. We definitely recommend that you learn and use GSAP 3

 

This is the bit confusing me the most, pinning is (usually) adding position fixed to elements to pin them, if they're already fixed I can't see how you're scrolling and pinning?

2 hours ago, Steve Giorgi said:

These are all fixed position so that I can "scroll" through each without actually having the appearance of scrolling while transitioning through each timeline.  I have a "master" timeline in each component (section) which pins to the screen.

 

Link to comment
Share on other sites

2 things that might work

 

1: put all the animation in one timeline I used this GreenSock starter demo 

See the Pen qBdzqmR?editors=1010 by GreenSock (@GreenSock) on CodePen

and made some slight modifications to achieve "multiple fullscreen slides that are sitting on top of each other with their own scrubbable animation"

 

See the Pen bGqvpqG?editors=1010 by snorkltv (@snorkltv) on CodePen

 

instead of sliding panels in, I just faded them in

 

2: position all your panels on top of each other but create a long page of "dummy divs" that is scrollable and contains child divs that act as the triggers for the animations in your panels (components)

 

Again, a demo may help, and from what you describe React isn't necessary to figure out the page setup or animation code. the simpler the better.

 

 

 

  • Like 3
Link to comment
Share on other sites

@CassieI'm not pinning and scrolling since each viewport/section is essentially already pinned.  I'm simulating scrolling which is actually just scrubbing through a timeline so that I can make animations appear and run through their respective timeline(s).  Each layer sits on top of another via z-index and transitioning between each can be any number of tweens/masks to reveal the underlying layers.  It's much like this great example of GSAP: https://solutions.centogene.com/.

 

@Carl Awesome.  Thank you for taking the time to modify this starter.  It's extremely helpful.  I was thinking about adding everything to a single master timeline but it adds a bit of complexity since you're tasked with forwarding all refs to each child component and each timeline within the current components is fairly sophisticated.  I think your second idea is awesome and that's exactly what the example site does except for dummy DIVs they pin and scrub through a WebGL layer.  I would simply make my dummy DIVs relative to the duration I need each of my component timelines to run, correct?

 

I'll definitely get a demo together if I request anymore assistance on this.  You've already gone above and beyond Carl.  I really appreciate it.

  • Like 1
Link to comment
Share on other sites

Glad to hear my suggestion might get you going in the right direction

 

32 minutes ago, Steve Giorgi said:

I would simply make my dummy DIVs relative to the duration I need each of my component timelines to run, correct?

Yeah, that sounds about right. There's a section at the bottom of the ScrollTrigger docs that explains how durations work with scrub:true

https://greensock.com/docs/v3/Plugins/ScrollTrigger but it sounds like you have a handle on it.

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

@Carl I ended up sending all my timelines up to a parent component and placed them into a master timeline.  This works beautifully.

 

I do have one odd scenario -- in my child timelines I was detecting the direction of the scroll so that I could use call() to fire detached timelines (that I do not want scrubbed) in forward and reverse as the user scrubs forwards and backwards through the main timeline.  Since my master timeline is now in my parent component, I can no longer signal the detached timelines sitting in my child components with the direction of my scrubbed timeline.  Can you think of any possible solutions?

 

The goal is fire those timelines that are detached from my scrubbed master but also have them in sync with my scrubbed master.  It's for doing things like bringing in text or UI that should not be caught mid-transition (UX).

 

 

Link to comment
Share on other sites

Yes, I believe you can use a custom hook to detect the scroll direction and/or trigger the timeline with useState from the main ScrollTrigger position; wasn't too sure about the best approach.

 

Using call() to trigger the timelines was a bit messy anyway -- for whatever reason reverse() would trigger at a different time than play() (with position assigned) and at times it would conflict with my main timeline.

 

I combined both of Carl's approaches and can now control multiple detached non-scubbed/scrubbed timelines in parallel by using a dummy container as the trigger.  I have a single master scrubbed timeline controlling all of my child components, and I'm firing detached non-scrubbed timelines while they are synced up with the master without the use of call() or reverse(); so it's extremely clean.  I'll post up a stripped down Codesandbox once I'm done with the project.

 

  • Like 2
Link to comment
Share on other sites

  • 1 month later...

@Carl

 

2: position all your panels on top of each other but create a long page of "dummy divs" that is scrollable and contains child divs that act as the triggers for the animations in your panels (components)

 

I was thinking about creating a scroll container proxy to act as the dummy (virtual dummy container), but then you'd lose the ability, at least easily, to setup trigger points on/in that container.  You would have to set a reference/ID as you iterate through creating the children containers within the main container and you'd essentially be left with the same setup.

 

In practice this works really well, it just doesn't feel very polished.  Would you really suggest this setup for a production site?  Do you have any thoughts about building a virtual proxy for these triggers instead?

 

--- in my particular case I have 10 main sections each with a very long dummy scroll/proxy container which sits positioned to the top of each main section.  Each of these dummy containers holds anywhere from 7-14 dummy children (100vh).  It makes a lot of sense but if you were to give all of that some physical appearance it would look like an absolute mess :D

Link to comment
Share on other sites

When initially responding here I was simply hoping to point you in a direction that might get you out of where you were stuck.  

I guess do what feels right for your particular project and skill level. Being that I have never touched React, makes it much harder for me to understand what you're working with or recommend anything near a "best practice"

 

 

 

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