Jump to content
Search Community

Pin element while animation plays but only once, then kill scrolltrigger/animation

swansondesigns test
Moderator Tag

Go to solution Solved by Rodrigo,

Recommended Posts

Hello,

 

I'm trying to piece together a solution based on some forum threads I've found but I can't get the effect to work.  The basic idea is this.

 

  1. The page is a stack of sections
  2. When you get to the "scene" section, the section is pinned and the animation within that scene scrubs until it completes
  3. The completion of that animation releases the pinned element
  4. When scrolling back UP, the animation stays in its final position (at the end) and the pinned section is now part of the normal document flow with no pinning.

 

Is this possible?

 

You can see here that I tried using onComplete to kill the ScrollTrigger (st) after the animation is complete, but it leaves the pinned section in the wrong spot.

const anim = gsap.from('section.scene p', { 
  scale: 0,
  // Using onComplete leaves the pinned element overlapping the adjacent section.
  // onComplete: ()=> st.disable()  
});

I also tried setting the ScrollTrigger only run once but that wasn't right either

const st = ScrollTrigger.create({
  trigger: 'section.scene',
  start: 'top top+=20',
  end: 'bottom top',
  scrub: true,
  pin: true,
  animation: anim,
  // Using "once" leaves space above the pinned element after scrolling past
  // once: true,  
});

 

The last thing I was going to try was just setting up another scrollTrigger to listen for the pinned element to be completely out of view and then reset the transform on the pinned section.  For some reason that seems like a hack (and not even sure it would work).  Is there something I'm missing?  I'm happy to create my own solution if someone can point me in the right direction.

 

Thanks,

Graham

 

See the Pen XWPEwvv by swansondesigns (@swansondesigns) on CodePen

Link to comment
Share on other sites

  • Solution

Hi Graham,

 

The solution is to use the kill method in the onLeave callback of ScrollTrigger and set the animation progress to 1:

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

 

https://greensock.com/docs/v3/Plugins/ScrollTrigger/kill()

 

Another option is to wrap the sections around a single parent and pin that element 

<div class="wrapper">
  <section class="normal"><p>Section 1</p></section>
  <section class="normal"><p>Section 2</p></section>
  <section class="scene"><p>Section 3</p></section>
  <section class="normal"><p>Section 4</p></section>
  <section class="normal"><p>Section 5</p></section>
  <section class="normal"><p>Section 6</p></section>
</div>
const anim = gsap.from('section.scene p', { 
  scale: 0,
});

const st = ScrollTrigger.create({
  trigger: '.scene',
  start: 'top top+=20',
  end: 'bottom top',
  scrub: true,
  markers: true,
  pin: ".wrapper",
  animation: anim,
  once: true,
});

 

Hopefully this helps.

Happy Tweening!

  • Thanks 1
Link to comment
Share on other sites

OK, I took this solution back to my project and it didn't work.  I played around with it and it seems to be caused by ScrollSmoother (which is part of my real project but I omitted from the minimal demo).  I have a new codepen to show it here:

 

 

So is this the scenario where I would use the alternate solution above where the entire stack of sections is wrapped in a container and then THAT container is pinned instead of the single section?  I would prefer not to do that if I can, but this project is really enhanced with the addition of ScrollSmoother so I'm reluctant to cut it out.

Link to comment
Share on other sites

I should have done this in the first place, here is my attempt at using the technique where you wrap all of the sections in a container and then pin that.

 

See the Pen poOZgmy by swansondesigns (@swansondesigns) on CodePen

 

I don't seem to be doing this one correctly at all because it doesn't work even without ScrollSmoother.  I have tried adding this to the onLeave function:

 

window.scrollTo(document.querySelector('.scene').offsetTop, 0);

 

That didn't do the trick.  Not sure what else to try.  Thoughts?

 

Thanks,

Graham

Link to comment
Share on other sites

  • 1 month later...

@GreenSock You are completely amazing.  Sorry for the delay in responding to this.  The project got paused for a bit so I'm just coming back to this now.

 

With your example I was able to get the effect to work in the live project.  Unreal that you support your customers this way.  I'm so, so thankful.

 

And thank you too @Rodrigo.  Everyone earned their capes on this one!  :)

 

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