Jump to content
Search Community

🚒 Need Help With ScrollTrigger Refresh Events

iDad5 test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

( I'm sorry for not being able to provide a simple CodePen right now. I hope you will understand my trouble without that.)

 

I have built a ScrollTrigger page before ScrollTrigger 3.11 and its' responsive updates. I'm not 100% sure if I would have / could have built it another way with 3.11...

My ScrollTrigger is Timeline-based, but I doubt that this makes a difference.

 

On the outside, it is a rather simple full-page full-picture panel construct.  But there is a catch: text (and a hamburger) on the picture-backgrounds that need to be readable. As I cannot predict upfront which text will be placed on what part of the picture, I must calculate the brightness/darkness of the areas where tests are placed. And I have to redo this with every resize.

 

A resize triggers the following sequence:

 

  • Kill the ScrollTrigger
  • scroll the Window to 0, 0 (necessary for my brightness canvas-based calculations)
  • check if I need better/larger pictures 
  • do my calculations 
  • recreate the ScrollTrigger
  • scroll the window with ScrollTrigger.scroll() back to the panel that was in view before the resize happened. (Recalculated to the new value if height has changed)

 

This used to work fine and was tested extensively. 

 It is broken now (I guess since 3.11). 

 

What happens now is the following: after the above sequence is finished:

  • ScrollTrigger updates and stays where it should be
  • onEnter is triggered—still fine
  • another update—still peachy

 

and then a refresh is triggered (belatedly after some requestAnimaitionFrame calls) and self.scroll() reports to be scrolled to the absolute bottom of the window.

(another update, where self.scroll() reports to be 0 and another refresh down to rock bottom follow)

 

I have set:

ScrollTrigger.config(
			{
				autoRefreshEvents: "load",
			}
		);

with hopes that this will avoid a (delayed) refresh to be triggered from the resize. 

It did not work.  

 

I do not understand why those two refreshes happen, nor do I understand why they scroll everything to the end of the ScrollTrigger.

 

Can anyone give me a hint? 

 

Edit: I found the 3.11.5 beta and tried it too—did not change the behavior. 

 

Edited by iDad5
Additional information
Link to comment
Share on other sites

Hi,

 

Have you tried with the enable/disable methods?

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

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

 

Although those could be a bit expensive in terms of resources and time.

 

Also is really required to scroll all the way up to check the canvas and the brightness of that particular area? I'm no expert in canvas but I assume that it has it's own coordinates system and that you could programmatically check those pixels without scrolling up and then back down. I understand that in canvas you can create a picture of an area using the toDataURL method:

https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL

 

3 hours ago, iDad5 said:

I do not understand why those two refreshes happen, nor do I understand why they scroll everything to the end of the ScrollTrigger.

I can't give you an answer for that but I can assure you that there is a good reason for this. I'm sure @GreenSock will provide it.

 

Sorry I can't be of more assistance but as you mentioned without a demo is a bit hard for us to do a lot.

Happy Tweening!

  • Like 1
Link to comment
Share on other sites

Thank you for your answer @Rodrigo.

I tried the disabled method back then extensively, but as the height of the window might have changed, the whole metrics for the ScrollTrigger had to be renewed.

As I mentioned, I might have worked with 3.11, but that just wasn't there. 

The scroll back is actually the only feasible solution I could come up with. I already do a lot “reverse -engineering” of CSS to get the correct position of the text-elements and grab the appropriate cut-outs from the image.
Because of media-queries and some other “conditionals” in the CSS system trying to get the entire thing calculated is beyond me—and should not be necessary—as the system worked very well before.

 

 It is only the second time in a decade that a minor version update breaks things with Greensock. I really hope for a hint how to not have that refresh happen. 
I need to fix it, I already invested a lot of time in research, and rewriting stuff, but I cannot bill my client for that. As much as it might be a good thing to rewrite the whole thing from scratch—I simply cannot afford it right now. The complete thing is just shy of a thousand lines of code in typescript alone, not to mention PHP and CSS.

I do hope for a magic hint from @GreenSock and fully expect to be humbled by it—feeling dumb for not having seen it myself. :-)

 

And yes, if needs be, I will (try to) build a CodePen instead of sleeping tonight. (Enough whining for the rest of the week—I promise.)

Link to comment
Share on other sites

OK—I am somewhat lost and tired right now, so please forgive me if I'm totally on a wrong track with this one:

 

While trying to fix my problem I decided to work on the mobile problems I never solved completely.
 

One of them was that when over-scrolling the page on mobile, the fixed content could be forced to be scrolled out of view. 

I considered that a bug in mobile Safari, related to the 'over-scrolling' as position: fixed elements should simply stay on the page (as long as I don't move them by design - shouldn't they?).

 

I was happy to read that mobile Safari finally (!) should honor 'scroll-behavior' and put in my CSS to NONE!. 
Now, after a lot of hair-pulling (debugging mobile…) I find that 'something' sets  a style to my page's body with scroll-behavior: auto ????

As all pages without ScrollTriggers do not have that and all with ScrolltTriggers have that, I'm starting to lose faith.

 

Is ScrollTrigger really messing with my page body's CSS?

Link to comment
Share on other sites

Hey @iDad5. You sound tired and frustrated :) Totally been there myself, especially when dealing with iOS issues. Maddening. 

 

Yes, ScrollTrigger has to set scroll-behavior on the <body> to PROTECT you from a bunch of problems that'd happen otherwise. This is a GOOD thing, trust me. 

 

As for the stuff you said broke in 3.11, I'm having a very difficult time understanding your descriptions or trying to diagnose it blind, sorry. Can you please provide a minimal demo that shows "this works before 3.11.x...but breaks in 3.11"? The simpler the better. And rest assured that I'm committed to making sure that any bugs are squashed. You've been around long enough to know how much effort we put into making things backwards compatible and not introducing breaking changes whenever we can avoid that. With such complex tools, sometimes things sneak in but we've got your back when it comes to ironing out problems. We just need to be able to see the actual problem (hence the need for a minimal demo). I'm not aware of any existing bugs that sound anything like what you're describing. That being said, I'm just recovering from a horrible stint with COVID (hospitalized twice in a week), so my brain's a bit foggy and I may be missing something obvious. 

Link to comment
Share on other sites

Hi Jack,

 

So sorry to hear that you had to go through such hard times. I do understand and sympathize.

I barely made it alive through the last months myself, for different but not altogether unrelated reasons, I suppose.

 

The troubles with webpages working only near to perfection should pale in light of this; classical first world problems.

 

I'm still challenged by your hijacking my body ;-) but probably you are the only living person I trust that you know so much better than me.

 

I'll have to decide between taking the time to build a 'minimal' demo or reworking the thing from the ground up—which might be beneficial anyhow but even more unpredictable. 

 

I'll give it one more try as a 'dry run' before I decide and if you don't feel like considering it, it is it's just fine, I do know and value your dedication as you hopefully know!

 

 

Is there a way to make ScrollTrigger not react to window resize. (The ScrollTrigger.config thing seems not to work.)?

 

Essentially what I have is a newly minted ScrollTrigger, placed at the desired position right after creation with scroll(position) and everything seems dandy.

Then a refresh is triggerd (I guess belatedly through 3 ticking animation frames, and I'll end up at the very bottom for some reason.) 

I tried to just set 'debugger' after scrollTrigger.scroll(position);

 

		this.createScrolltrigger();
		console.log('actual scroll after scrollTrigger creation: ' + document.documentElement.scrollTop);
		// logs 0 as expected'
		this.scrollTrigger.scroll(targetWinScrollTop);
		console.log('actual scroll after scrollTrigger scroll(): ' + document.documentElement.scrollTop);
                // logs targetWinScrollTop's value
		debugger;
                // BUT: the scrollbar on the browser-window is fully on top, the panel shown is always the last one...
                // Probably the sudden stop happens before any page render, so that might not be of any use..

My script does nothing after that sequence.

 

I have, however, added those lines to my ScrollTrigger creation:

 

onEnter: self => {
	console.log('Entering scroll trigger at:' + self.scroll());
},
onUpdate: self => {
	console.log('updating: ' + self.scroll());
},
onRefresh: self => {
	console.log('🟡 scroll trigger refresh: ' + self.scroll());
}

and with my target scroll being 1680 I get the following output, when debugger is commented out:

The last trace from my script:

 

> actual scroll after scrollTrigger scroll(): 1680 // from 

 

then: 

 

 > updating: 1680
> entering scroll trigger at:1680

> updating: 1680

> 🟡 scroll trigger refresh: 5072

> updating 0

> 🟡 scroll trigger refresh: 5072

 

Window position is by display and programmatically 5072 then and also the 'endScroll' event is fired once and proves the position (and the reached last  label) programmatically.

 

 

Link to comment
Share on other sites

10 minutes ago, iDad5 said:

Is there a way to make ScrollTrigger not react to window resize. (The ScrollTrigger.config thing seems not to work.)?

I was a bit confused by your comment. Why do you think it doesn't work? 

ScrollTrigger.config({
	autoRefreshEvents: "load,DOMContentLoaded" // notice there's no "resize"
});

Notice that after that, the onRefresh() won't get called when resizing:

ScrollTrigger.create({
	start: 0,
	end: "max",
	onRefresh: self => console.log("refresh")
});

Right? 

 

11 minutes ago, iDad5 said:

Then a refresh is triggerd (I guess belatedly through 3 ticking animation frames, and I'll end up at the very bottom for some reason.) 

This sounds odd to me. 

 

Can you please verify that you're using 3.11.4? There was a caching issue with scroll values in an early 3.11.x version, but that should be fixed in 3.11.4. I'm still not sure why you're saying you end up at the very bottom scroll-wise too. I'm super curious to see a minimal demo

Link to comment
Share on other sites

Also I'm not 100% sure what triggers the refresh, as the ScrollTrigger is minted newly after the resize (I react only to the resize after a delay of 3oo ms) the whole refresh is strange—the three animation frames were traced out somewhere, and thus I guessed that it must have to do with the resize somehow…

Will investigate and demo…

Link to comment
Share on other sites

While preparing the demo, I found some hints that could point to the root of the problem:

When I killed the ScrollTrigger, I did it with the defaults. That makes the ScrollTrigger obviously trying to revert things back, and likely might interfere with what my script tries to do.

In the end it shouldn't matter much, as I do reset everything anyhow and set up things from the start once again. Interestingly though, when I use kill(false) I do get less interference, but the “pinspacer” is not cleared, and I get another one when recreating the ScrollTrigger. Oddly enough, though, I never get more than 2. 

 

I hoe that I will have the demo online soon.

Link to comment
Share on other sites

Here we go. The demo is not truly minimal, but I do hope it helps.

 

Experimenting with kill(false)  in the end got me nowhere, it just got more buggy all around. Still, I think that kill somehow is to blame for my troubles.

 

I've added a lot of consle.log and traces to everything the ScrollTrigger does. (You need to use the dev-tools, the CodePen console won't do—no trace there, for example.)

Especially the onRefresh log 🟠 is what bothers me. 

 

In line 108 (createScrolltrigger method) I supposedly configure autoRefresh to only run at DOMContentLoaded  but it runs with a resize (twice)—in the trace stack it seems however that it is triggered by kill()—is this possible?  (I do call kill() after a resize)

 

See the Pen LYBgVON by iDad5 (@iDad5) on CodePen

 

You can also test a plain version at: https://dev.thewebworks.de/playground/panels/

 

To reproduce: scroll to the second or third panel and resize the window. With a short delay, everything is reset and reordered, and with 'reInstateScrollTrigger' the Panel that was on display before the resize is scrolled into view. (Line 98) That works as intended (some entering, starting and updating is going on, but no harm done there).

But then a refresh sets in and runs everything to rock-bottom. 

 

The script is still rather complex, but most of the functions should be self-explanatory and don't really play a part in my troubles. I left some of it in, to give a glimpse of why I chose to kill and rebuild the ScrollTrigger I'm not 100% sure if with the new version, I could do it another way. 

 

I do need to 'collapse' everything on resize though to do those brightness calculations and after those are done, I want to scroll back to the previously shown panel. With a change in window height, the scroll-position needs to be recalculated thus. 

 

Link to comment
Share on other sites

Quote

The script is still rather complex, but most of the functions should be self-explanatory and don't really play a part in my troubles. I left some of it in, to give a glimpse of why I chose to kill and rebuild the ScrollTrigger I'm not 100% sure if with the new version, I could do it another way. 

 

That's a huge amount of code there. Honestly I opened it up to help, looked at it all and closed it again. 🙈 

We'd really like to see whether this is a ScrollTrigger bug so if you could cut out all of the code apart from the absolute essentials that would be wonderful. Sorry to ask for more effort on your part - but 400 lines of JS is quite a lot to sift through. 

 

Link to comment
Share on other sites

Just scrolled up and saw that it was was working in previous versions. Oh man, that's frustrating, sorry.

I'll have a little test of some previous versions for you. 👀

In the meantime maybe this could be a base for a simplified down version?

Edit - Gave it a simplification, if you could show us the issue on this pen that would be grand. Thank you!

See the Pen qByJowo?editors=0011 by GreenSock (@GreenSock) on CodePen

  • Like 3
Link to comment
Share on other sites

Thank you so much @Cassie, but that is a bit beside the point.

I do understand how tedious it can be to read all my palaver—but the thing is not so much the simple demon looking for mistakes, (I do make them all the time with passion…)

In this case, it seems to boil down to the point of ScrollTrigger kill().

 

I have (or at least had—in my simple mind) a very convincing reason to kill and recreate my ScrollTrigger. And it use to work.
Now I can either keep the default kill() which, leaves a refresh “hanging around” that disturbs the system, or if try kill with (false) which seems not to do a proper clean-up as it leaves me with a doubled pin-spacer and in the wake of it—an unpredictable mess.

 

Your code, which is much cleaner and cleverer than mine, simply does not kill and recreate the ScrollTrigger, so your effort isn't helping to pin down the issue,

As I stated clumsily in my other posts, I'm uncertain if there was or at least is now a much better way to solve my problems, but a) I wanted to help to track down a possible breaking issue and b) hoped to avoid opening the much more complex box of worms that the actual code is.

 

I can simplify my demo-code some more, but the code itself will simply look silly, as there is no trace of the need for killing and recreating the ScrollTrigger left anywhere….

 

As good as the pure (CodePen) demo way of tackling issues mostly is, I feel it has limitations in some cases. Like the one at hand.

Link to comment
Share on other sites

I understand that my codepen isn't showing the issue - I was prompting you to layer on complexity until it breaks. My demo is too simplified. Your one is far too complex for most people here to help with. I (and many others here) don't understand typescript - help us out - meet us halfway.

 

Quote

I can simplify my demo-code some more, but the code itself will simply look silly, as there is no trace of the need for killing and recreating the ScrollTrigger left anywhere….

That's fine - silly code lacking in context that clearly shows the issue. Perfect. That's what we want!

 

Quote

Your code, which is much cleaner and cleverer than mine

My code isn't cleverer, it's not even mine! It's just a smaller section of your demo which I copy pasted and cleared up a little.

It sounds like you just need to add that kill() call somewhere to show us what the issue is?

Link to comment
Share on other sites

9 minutes ago, Cassie said:

(Also worth mentioning again that Jack's sick so it's just the lowly mortals trying to help here)

That is what I feared. Please let him know—if somehow possible and sensible—that we all need him to stay in bed and get well. Work be damned, people matter.

 

I did remove the crucial part of calling the panels to do their calculations—and everything works just dandy. (Insert some swear-words here—or don't) 

except it does not, when resizing twice or thrice… 

 

My wild guess would be, that somehow completely killing off the magic thing that ScrollTrigger is working quite well when nothing else is going on. But when a lot of other stuff is “going on”, listeners will be left behind to haunt me. Probably I can find a way to do the calculations in a worker thread and not wait for them to finish before recreating, …

If I sound lost here it is because I am, and the trouble in this case is, that debugging this system is no fun under easy circumstances.

 

I will give it some thought and a try as soon as I can afford it.

 

See the Pen PoBydmo by iDad5 (@iDad5) on CodePen

 

I guess that leave us mortals where we have always been…

 

Thank you so much for your help!

 

Link to comment
Share on other sites

Actually, I'm rather certain that it has nothing to do with the initial delay of 300ms. (As far as certainty goes for a mere mortal).

 

Nothing happens before those 300 (Spartans) are over. What happens then might be the dance of death.

 

I call the ScrollTrigger to go kill itself and next line my panels to recalculate themselves.  

 

Those calculations do involve waiting out several animationFrameRequests, as I need to make sure the elements I have to measure and analyze are in the position I need them to be, having been transparent, scaled and cropped before. 

 

ScrollTrigger's “default kill” however wants to rewind its animations before it leaves the stage and therefore (very likely) will also make sure that the necessary animation Frames have passed by, not to leave everything in a mess. (I got the idea through the stack traces of onRfresh, where delayedResize calls handleResize that calls kill and then a variable number of animationFrameRequests happen before the updates.

 

I am convinced that ScrollTrigger.kill uses a very sophisticated system to make sure it does its job of reversing the animations perfect. But my calculations that are intensive (albeit not too time-consuming overall) likely hold the actual “clean-up before I die” execution back or trigger said race condition. Even my dummy version in the first demo did the job “reliable” it seems. 

 

ScrollTrigger.kill(false) could/should be the solution, but there (I guess) might be the rare bug that escaped Jack and all you demigods, as it seems to do no proper clean-up.  of the pin-spacer at least.

But all of that is just idle speculation, and not worth bothering anyone but me. :-)

 

Should have found a better solution in the first place, or told the client, that their wishes are BS... 

Link to comment
Share on other sites

37 minutes ago, Cassie said:

I wonder if it's a race condition that was, just by luck of timing, flying under the radar before?

That I would rule out with some certainty, as the original version was an extensive pain in the behind, and once it worked, we tested it to the moon and back. I think it more likely that the extension and optimization of ScrollTrigger's (responsive) features had this unlikely side effect with my unlikely code.  

Link to comment
Share on other sites

  • Solution

I spent a few hours digging into this with my foggy COVID-brain and I think I found the very rare edge case related to snapping and the fact that when you apply a ScrollTrigger to a timeline it has to wait for a tick before it actually refreshes that instance (otherwise the timeline would likely be empty...people create timelines and THEN populate them so we can't do the refresh() right away). 

 

Here's a beta file: 

https://assets.codepen.io/16327/ScrollTrigger.min.js (you probably need to clear your cache)

 

Better?

 

Also, I wanted to make sure you understood that when you did your ScrollTrigger.config({ autoRefreshEvents: "..."}) stuff, that only affects when a full ScrollTrigger.refresh() gets called automatically (for ALL ScrollTriggers). But each individual ScrollTrigger has to refresh() initially when created, otherwise they wouldn't have any start/end values :) It looked like you were surprised to see the onRefresh() callback triggered when you were re-creating your ScrollTrigger(s) on resize, but that's totally normal. Let me know if you need more clarity around that.

 

Does the beta file behave the way you'd expect? It was quite a challenge to try to follow the 400+ lines of your TypeScript demo in my condition 🙃 In the future, I'd definitely recommend trying to strip things back further. Like if the problem is that resizing results in the scroll jumping to the very end, maybe try to do the most basic demo possible and if it works, start layering things on (like in this case, you'd need snapping). Then the moment it breaks, you know exactly what it was and we can avoid all that extra complexity.  I know you were trying to be helpful with all those logs/traces. It was a bit of information overload, and there were so many pieces all firing at various times which I think just made it more convoluted than it needed to be. I do appreciate the intent. Hopefully the beta resolves things for you though and you don't need to mess with the demo anymore. Thanks for putting the effort into creating the demo! I know it's always a challenge. Creating a minimal demo is quite an art form, I know. 

  • Like 4
  • Thanks 1
Link to comment
Share on other sites

@GreenSock: Thank you so very much, Jack!

I somehow feel bad that you did this while you are ill, but I won't question your decision. :-)

 

The new version works exactly as intended. 

3 hours ago, GreenSock said:

Also, I wanted to make sure you understood that when you did your ScrollTrigger.config({ autoRefreshEvents: "..."}) stuff, that only affects when a full ScrollTrigger.refresh() gets called automatically (for ALL ScrollTriggers). But each individual ScrollTrigger has to refresh() initially when created, otherwise they wouldn't have any start/end values :) It looked like you were surprised to see the onRefresh() callback triggered when you were re-creating your ScrollTrigger(s) on resize, but that's totally normal. Let me know if you need more clarity around that.

 

Thank you for the explanation, I wasn't surprised to see the onRefresh() after the creation of a ScrollTrigger instance—I would have been if I hadn't seen it, I guess. My musings were meant to help those overwhelmed by all those logs, but it seems they did not.

 

4 hours ago, GreenSock said:

Hopefully the beta resolves things for you though and you don't need to mess with the demo anymore. Thanks for putting the effort into creating the demo! I know it's always a challenge. Creating a minimal demo is quite an art form, I know. 

 

It is, and I was aware that I'wasn't doing a very good job with it. I did start out with a real minimal demo at first, but after several tries and 2 plus hours of trying I couldn't reproduce the issue. As I had the previously working very complex example, I finally went on reducing 1200 Lines of code to 400, where I hoped that It would be easy to ignore half of it. I will try to do better next time. 

 

Again thank you and @Cassie and @Rodrigo too for being very helpful and patient as always!

I wish you fast and full recovery, Jack and send you a big package of thankful thoughts.

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