Jump to content
GreenSock

Steve Giorgi

ScrollTrigger - Disable/Enable

Recommended Posts

Re-enabling disabled ScrollTriggers after the scroll position has changed returns the viewport to the original position.  

 

Can ScrollTriggers be re-enabled without having the viewport be reset?

Link to comment
Share on other sites

I'm using 3.7.0.  I'll update now.  I have 35 ScrollTriggers on one page within my current project.  I'm iterating through all and disabling.  Firing a window position with ScrollToPlugin and re-enabling all ScrollTriggers.  Disabling works beautifully, ScrollToPlugin works beautifully, but upon enabling them, the viewport snaps right back to the original position and/or to the very top of the page.

 

I'll see if I can pin down the same behavior with a few ScrollTriggers in Codepen.  I was hoping I could pass a parameter to .pause() or .enable() --- something simple to keep the viewport at the new location.

  • Like 1
Link to comment
Share on other sites

@GreenSock I updated to version 3.7.1.  Now, let me preface this by saying I only broke out each ScrollTrigger to mimic my current project --- each has it's own set number of pinned screens to scroll through and other parameters that make each unique in the actual project.  I also have dummy containers which trigger several ScrollTriggers within each section; I mimicked that here as best as possible without making it too convoluted.

 

The dummy containers were Carl's recommendation and it does work really well --- in the context of this demo they don't make sense but I wanted to be sure to get them in there to mimic the overall setup.  I made it as simple as possible and broke everything out so that it's very clear.

 

https://codesandbox.io/s/sleepy-cdn-9f3sm?file=/src/pages/index.js

 

If you scroll through it and click on an anchor it will jump to the correct section and immediately jump back.  This may be the correct behavior for how I'm toggling the ScrollTriggers off/on but as an end user it's difficult for me to know that for sure.  If you disable the onComplete: line 180 and click on an anchor; it works as expected.  In the context of anchors or at least in my application of them, you'd want to move the user to that section and then re-enable the ScrollTriggers so that they can continue through the animations contained in that section.

 

 

 

 

Link to comment
Share on other sites

1 hour ago, OSUblake said:

Can you put that in a CodePen? Gatsby is so difficult to work with on codesandbox.

 

Yeah, it's not working at all for me. Tries compiling for a while and then "refused to connect". Can't see anything. 

 

It should be pretty easy to work around the issue you described, though. When you go to enable them again, just manually restore the scroll position...

let all = allScrollTriggers.current,
    position = all[0].scroll(); // save the current scroll position
all.forEach(trigger => trigger.enable());
all[0].scroll(position);

But of course if there's a bug we need to fix, I'm happy to do so. It'd just really help if we could see a functioning minimal demo :)

Link to comment
Share on other sites

I think it's the expected behavior, just in my scenario it works against me.

 

OK, I'll grab the position after I've disabled the ScrollTriggers and moved my window/viewport with the ScrollTo anchors.  I will then enable the ScrollTriggers and manually set the position to the position stored right before the ScrollTriggers were re-enabled; this sounds very logical.  Thank you.

 

 

I think this kind of sums up the issue I'm seeing:

 

I have several ScrollTriggers which creates scroll distance for the pinning to take place.  I disable them, I move my window position with ScrollTo to one of the containers but all of the distance has also been removed (since the ScrollTriggers have been disarmed).  I enable the ScrollTriggers and it moves my window/viewport relative to where it was previously, which is way up the page and nowhere near where my anchor dropped me.  This sounds like correct behavior to me --- but, then, how can we account for anchor links --- in my case, the pinning has to be disabled because the scrollTo action hits those ScrollTriggers causing the animation to run through very quickly running to the end and sometimes overlapping/breaking.

 

I'll see if I can move my demo over to CodePen.  It took several hours to build the current demo (thank you both for trying to have a look).

Link to comment
Share on other sites

Does the ScrollTrigger pinning add spacing to the entire document or is the spacing isolated the the div that is created on the fly?  Does your vertical scroll position change when the ScrollTriggers are active/inactive -- obviously it changes within the section you're pinning but how about outside of it?

Link to comment
Share on other sites

I wonder if this wasn't working because I pasted a link to a specific component: https://codesandbox.io/s/sleepy-cdn-9f3sm

 

I tried creating this same demo in Codepen but I don't have access to the same hooks.  I'm trying to replicate the behavior without the React stuff.

Link to comment
Share on other sites

The link was fine. It just tells CodeSandbox what file to display. Gatsby is just clunky on CodeSandbox and is not needed to demonstrate the issue. If you must use Codesandbox, use this template.

https://codesandbox.io/s/gsap-react-starter-ut42t

 

Or CodePen.

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

 

But it's usually best to show issues in vanilla JS as a lot people on this forum don't know React, so you're limiting the number of people you can get help from. And it's usually easier to isolate the problem without a framework getting in the way.

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, Steve Giorgi said:

Does the ScrollTrigger pinning add spacing to the entire document or is the spacing isolated the the div that is created on the fly?  Does your vertical scroll position change when the ScrollTriggers are active/inactive -- obviously it changes within the section you're pinning but how about outside of it?

It adds paddingBottom to the pinned element. Usually that pushes things down on the page below it, but that really depends on how you set up your CSS/layout/markup. So yes, if the paddingBottom pushes things below it down further on the page, it would affect the height of the overall page. Again, depending on how you've set things up, of course. If you've got the pinned element inside a <div> that has a fixed height and overflow: hidden, for example, that wouldn't allow things to expand. 

 

When you call .disable(), there's a revert parameter which is true by default. That causes it to rewind any associated animation and unpin things. 

Link to comment
Share on other sites

@GreenSock thanks Jack, that clarifies several questions.  I didn't realize I could set everything to a fixed height and hide the overflow -- I thought that would impact how ScrollTrigger behaves.  That makes it much easier to calculate the position in different scenarios.  I also see revert and refresh options are part of the self.enable() function but I didn't see those documented.

 

@OSUblake I created as minimal of a Codepen demo as possible.

 

I'm pretty sure this behavior is correct but I'm trying to find a work around for anchors.  Within each section would be many other ScrollTriggers with their own timelines; each section is pinned for the duration of those animations.

 

I also tried Jack's suggestion -- I am able to save and set a scrollTo position with overwrite: "all", after re-enabling the ScrollTriggers and it does move the viewport to that position (the position is off due to paddingBottom but this can be calculated/accounted for other ways), but several of the ScrollTriggers end up firing (timelines become overlapped).

 

I looked at the self.enable function -- the viewport is reset when self.enabled is set to true; but as you know that's tied to a ton of logic.  I'm hoping to just toggle the ScrollTriggers off, move the viewport, toggle them back on so the current section (and all other sections) continue pinning.  Use case would be for anchors and other functionality that might require going through all of the ScrollTriggers very quickly --- another example: scroll to top button.

 

See the Pen jOmeBwK by steve-giorgi (@steve-giorgi) on CodePen

 

I'm forking the demo to see if I can replicate the behavior described above when saving/restoring the position.

 

Link to comment
Share on other sites

I'm just wondering if this is normal behavior.  If it is, then I'll figure out a way to get the user to the correct position when they hit an anchor.  Storing the scroll position before the ScrollTriggers are enabled and restoring the position sends the viewport to an incorrect position (incorrect in the sense that the saved position is somehow not the same when the triggers are re-enabled).  It ends up pinning/triggering the other ScrollTriggers around it.  I wasn't able to replicate the secondary issues I described -- pretty sure it's a logic issue on my part.

Link to comment
Share on other sites

I think there's probably a much better solution that disabling/enabling all the ScrollTriggers every time you want to do a scrollTo. 

 

I've come up with several options for you...

 

1) Use a variable that indicates whether the animations should be "disabled" and use a simple function that's attached to the onUpdate that'll force the progress to only be 0 or 1: 

 

// if disabled is true, don't allow the ScrollTrigger's animation to render at any progress other than 0 or 1.
function checkDisabled(self) {
  if (disabled) {
    let tween = self.getTween();
    tween && tween.progress(1); // in case there's a scrub attached
    self.animation.progress(self.progress === 1 ? 1 : 0);
  }
}

 

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

 

2) You could use an even simpler function (an no variables at all) for the onUpdate that would check the scroll velocity and when it exceeds a certain amount (I chose 2500px/second arbitrarily), it eliminates the scrub animation. Technically it just forces it to its end immediately:

 

// when the scroll velocity is more than 2500px/second, skip the smooth scrubbing
function killWhenFast(self) {
  let tween = self.getTween();
  tween && Math.abs(self.getVelocity()) > 2500 && tween.progress(1);
}

 

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

 

The up side: this also works when the user scrolls very quickly on their own. The down side: you do see the animation happening while scrolling, but there's no lag in the scrubbing so there's no risk of overlapping animations. 

 

Does that help?

Link to comment
Share on other sites

Thank you very much for taking the time to have a look and come up with some solutions.  I can definitely think outside of not disabling/enabling the ScrollTriggers but the animations do rely on triggered animations rather than scrubbed.  I think your first option will work for both types!

 

Your second option is extremely clever --- I could see that working with/without scrubbed animations.  I don't think either solution relies on the animations being scrubbed, right?  Both solutions really make me start to think outside of the "box".  For instance, instead of snapping position in a carousel to combat someone scrolling too quickly, we could snap the position based on velocity.  Thank you Jack.

 

Edit: This was very testable --- your idea about velocity checks is really exciting.  Got ahead myself.  It looks like both options will work with triggered animations as well.

Link to comment
Share on other sites

20 minutes ago, Steve Giorgi said:

but the animations do rely on triggered animations rather than scrubbed

That's totally doable too. Just attach a function like this to the onToggle:

function killWhenFast(self) {
  Math.abs(self.getVelocity()) > 2500 && self.animation.progress(self.progress === 1 ? 1 : 0).pause();
}

 

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

 

The only other thing to keep in mind is that your code is doing scrollTo based on where the element is in the document flow at that point, but keep in mind that pinning effectively moves the element down to the bottom of its area when it becomes unpinned. So if you want your links to go to the original position(s), you'll need to handle things a bit differently. There are probably a few ways to accomplish that. If you need help, let us know. 

 

Good luck!

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