Fifteen4 Posted November 19, 2022 Share Posted November 19, 2022 Greetings, friends! So let me start by saying I've been happily using GSAP for about 7 years now and have been absolutely thrilled with it! Seriously, you all are a bunch of geniuses — this thing just works. I've been churning through a bit of a head scratcher recently, though, so I've finally decided to come out of my lurker mode and ask a question! I was trying to nail down some weird jumpiness in pinning full-height ScrollTrigger (and ScrollSmoother) elements on mobile devices. I'd worked through all the usual issues with this (mobile viewport resizing, browser address bar nonsense, etc.) with almost complete success, but just couldn't get the element to sit still upon first touching to scroll. I noticed that the issue was most prominent when scrolling shortly after letting a snap finish its work, so I removed snapping (literally just commented out the config line) and sure enough — it was perfect again. So it begs the question — am I missing something with the snap functionality? Is this a known issue on some devices? It's gravy on desktop devices, but gets finicky on my android (the only mobile device I've tested so far). Have I lost my mind? Any ideas would be appreciated forever ❤️ Here's some info that could help: Device: Google Pixel 6 Pro OS: Android 13 Browser: Chrome for Android v 107.0.5304.105 It's best to look at the pen in full-screen mode. I've also taken a screen recording that demonstrates it. There's a slight jank visible on the very top and bottom most of the time, but the most striking occurrence of the issue happens around 7 seconds in. Thank you all! screen-20221118-211410_2.mp4 See the Pen LYrOMex by nick-patterson (@nick-patterson) on CodePen Link to comment Share on other sites More sharing options...
GreenSock Posted November 19, 2022 Share Posted November 19, 2022 19 hours ago, Fifteen4 said: but just couldn't get the element to sit still upon first touching to scroll. I noticed that the issue was most prominent when scrolling shortly after letting a snap finish its work, so I removed snapping (literally just commented out the config line) and sure enough — it was perfect again. Hm, so are you saying that the pinning itself seems to be vibrating a bit as you touch-scroll, but only on Android and only if you have snapping enabled? Is it only happening after you release (which is when snapping would take effect) or the whole time you're touch-scrolling? I'm having a tough time seeing it in the video, but I'm probably just missing something obvious. I'm curious if you notice any difference by adding will-change: transform on your pinned element and/or any child that you see "vibrating". Some browsers seem to do odd sub-pixel rendering unless you enable will-change (strange, I know). 19 hours ago, Fifteen4 said: So let me start by saying I've been happily using GSAP for about 7 years now and have been absolutely thrilled with it! Seriously, you all are a bunch of geniuses — this thing just works. I've been churning through a bit of a head scratcher recently, though, so I've finally decided to come out of my lurker mode and ask a question! This is so nice to hear! Glad you're coming out of "lurker mode". And thanks for being a Club GreenSock member! 💚🥳 Link to comment Share on other sites More sharing options...
Fifteen4 Posted November 20, 2022 Author Share Posted November 20, 2022 20 hours ago, GreenSock said: Hm, so are you saying that the pinning itself seems to be vibrating a bit as you touch-scroll, but only on Android and only if you have snapping enabled? Is it only happening after you release (which is when snapping would take effect) or the whole time you're touch-scrolling? I'm having a tough time seeing it in the video, but I'm probably just missing something obvious. That's most of it! It's definitely restricted only to android (for now) and only when snapping is enabled. The main issue (more so than the top/bottom "vibrating") is that the pinned element seems to come entirely "unpinned" for a brief moment when attempting to scroll very shortly *after* a snap finishes. In my video, the most notable example of this is when the big white block appears at the bottom (or rather when the pinned element is no longer pinned, thus revealing the white body background underneath) just as my scroll begins at around 7 seconds. At this time, you can even see the little circles pop up towards the middle — these are what my fingers are doing when the problem arises. Does that help? 20 hours ago, GreenSock said: I'm curious if you notice any difference by adding will-change: transform on your pinned element and/or any child that you see "vibrating". Some browsers seem to do odd sub-pixel rendering unless you enable will-change (strange, I know). Having just tried this, it seems to have had very minimal (if any) effect, unfortunately :(. I added the will-change prop to varying combinations of the pinned element, the scrollSmoother containers, etc. just to cover all of my bases. Thanks so much for looking at this! Link to comment Share on other sites More sharing options...
GreenSock Posted November 20, 2022 Share Posted November 20, 2022 Hm, that actually sounds like an Android bug most likely. Let me explain the dynamics... Most browsers handle scrolling on a completely different thread from JS (and everything else). So think of it as if that thread took a screenshot of your entire page, and then when you press to start scrolling, it just renders it as if that screen capture moved with your finger. But all JavaScript (including ScrollTrigger) can only run on the main thread, so then when that updates, it's like "oh, that element should be pinned...render it that way please", so it jumps back into the correct position. It's absolutely impossible (as far as I know) for ScrollTrigger to force those threads to remain in sync. That's why we came up with normalizeScroll which is the best we can do - it essentially says "whenever you have a touch event, don't do what you'd normally do (like scroll) - instead, we'll use JavaScript to handle the scrolling." You've got normalizeScroll, so it should be cancelling the "normal" scroll but the behavior you're describing sure sounds like it's not in that case. I've seen Android devices handle the first touch event in a very odd way (not according to spec). I wonder if it's inappropriately ignoring our request to preventDefault() on that event. What's most confusing for me is that you're saying it's resolved if you disable snapping. Can you tell me if it's only happening if you try to scroll WHILE it's still snapping? Maybe make sure you wait long enough inbetween scrolls. Let the snapping COMPLETELY finish, then scroll again - do you ever see an issue when you do that? And remember, the snapping may take slightly longer to finish than you visually see due to easing. I'm trying to discern what exactly might be happening when you see the issue. If snapping isn't even happening, it wouldn't make much sense that disabling snapping would solve the issue. Snapping has zero effect on the normalizeScroll functionality - it's not as if snapping enables native scroll again. The more details you can provide about EXACTLY how to reproduce the issue, the more likely we'll be able to track it down. Link to comment Share on other sites More sharing options...
Fifteen4 Posted November 20, 2022 Author Share Posted November 20, 2022 @GreenSock hmm that makes sense in context here. The issue seems so intermittent and bizarre that a browser (or OS) rendering/event propagation bug wouldn't surprise me one bit. Let me try and test both of these cases for you: Scrolling WHILE Snap is in progress: - Upon timing my scroll to "interrupt" the snap while I can definitely see the scrollbar still moving (so before the ease would really start to slow things down), I'm able to recreate the issue somewhat reliably. - In doing this, the issue seems to vary between some slight "vibrations" (20px or so of white background flashing at the top/botttom) all the way to the severe phenomena like the large white space shown in the video. Both of these would flash right at the moment of touch, then subside after a split second. - One *very* interesting thing I noticed is that the severe phenomena seems to only crop up when I "interrupt" a snap by scrolling in the SAME direction the snap is working towards. In fact, I was able to (twice) seemingly break things entirely, meaning the element remained "unpinned" even AFTER the snap completed (I waited probably 10 seconds) — only re-pinning if I were to scroll again. In digging further, it seemed like interrupting a snap by scrolling in the OPPOSITE direction of where a snap was working towards would only yield the vibration, not the severe phenomena. - Regarding the above, It might be worth noting that my android is using the "natural" scroll interaction (inverted?) — meaning that the page scrolls UP when my finger moves DOWN. Since the severe phenomena seems to pop up only when interrupting a snap by scrolling in the same direction as the snap, could there be something with the delta in touch start/move/end in that case? I don't know if this is even at play here, but this certainly threw up a red flag for me. Scrolling AFTER the snap finishes - After taking your recommendation and waiting for the snap to completely finish, I wasn't able to replicate the severe phenomena at all — regardless of direction. - I was, however, able to still replicate the vibration phenomena. It's worth noting that this doesn't occur at all when snap is disabled — in either direction. Does this help? Link to comment Share on other sites More sharing options...
GreenSock Posted November 22, 2022 Share Posted November 22, 2022 Thanks for the data, @Fifteen4. I cannot replicate the issue at all on my Android device. Would you mind experimenting with this?: // old snap: "labels" // new snap: { snapTo: "labels", onStart: self => { self.getTween(true).eventCallback("onUpdate", () => { self.scroll.cacheID++; ScrollTrigger.update(); }); } } I'm just curious if that helps at all on your device. As for the direction of scroll, I don't think there's any code in ScrollTrigger that'd act differently like that, so that certainly sounds like a browser-level glitch. 🤷♂️ Link to comment Share on other sites More sharing options...
Fifteen4 Posted November 23, 2022 Author Share Posted November 23, 2022 @GreenSock thanks for getting back! I certainly will add that and report back! Link to comment Share on other sites More sharing options...
Fifteen4 Posted November 23, 2022 Author Share Posted November 23, 2022 @GreenSock so interestingly, this addition prevents the severe issue from popping up entirely. I wasn't able to reproduce the large boxes or complete "unpinning" at all after adding it. What does that mean in the context of the snapping? There is still the slight vibration happening (absent with no snapping enabled), but there's not anything nearly as drastic as before. I'm still entirely confused, but thank you so much for the improvement! Link to comment Share on other sites More sharing options...
GreenSock Posted November 23, 2022 Share Posted November 23, 2022 Very interesting. Would you mind trying this (beta) version of ScrollTrigger and letting me know if it resolves things? You do NOT need to use that onStart stuff from my earlier post - just snap: "labels" is fine. https://assets.codepen.io/16327/ScrollTrigger.min.js (you may need to clear your cache) Link to comment Share on other sites More sharing options...
Fifteen4 Posted November 23, 2022 Author Share Posted November 23, 2022 @GreenSock Haha a beta test!? For Greensock!? Oh — the pleasure is all mine. After playing around with it for a while — trying all of our tests we've discussed and covered — I have to say it's a similar story as with the cache-busting onStart callback you gave me earlier today — the severe issue is entirely absent. The vibration, however, remains, but to a seemingly more subdued extent and limited only to the top of the viewport. Adding back the will-change props (to the pinned element and the scroller content) doesn't seem to have any effect — but given that I'm trying all this in the same CodePen example I posted above, I wonder if CodePen's iFrame is responsible for this effect on Android. The apparent difference in behavior relative to scrolling direction is also now irrelevant — the vibration just remains at the top (right under CodePen's minimal UI) when attempting to scroll during or after a snap. Perhaps a truly isolated full page may be treated differently? I can try this again in an isolated sandbox (no CodePen iFrames) tomorrow, but regardless, this is a significant (huge) improvement. Thanks so much for the improvements already — and I'll update you tomorrow. Link to comment Share on other sites More sharing options...
GreenSock Posted November 23, 2022 Share Posted November 23, 2022 16 hours ago, Fifteen4 said: the severe issue is entirely absent. 🥳 As for the "vibration", that likely has to do with how the browser is rounding things. I can't replicate that anywhere, sorry. Would you please try this beta version of ScrollSmoother (on CodePen/CodeSandbox/Stackblitz only) and set wholePixels: true in your config object?: https://assets.codepen.io/16327/ScrollSmoother.min.js ScrollSmoother.create({ wholePixels: true, // <- only for testing, not official API smooth: 2 }); Does that help anything with the vibration? I kinda doubt it will, but I'm curious about your device. Link to comment Share on other sites More sharing options...
Fifteen4 Posted November 29, 2022 Author Share Posted November 29, 2022 Hey @GreenSock Sorry but I totally lied about getting back to you when I said I would! Haha evidently I forgot about Thanksgiving. If you celebrate, I hope yours was a wonderful one. In trying these betas out, the results are the same. The severe issue is gone entirely, but the vibrations and slight unpinning during/after snap still remains. I think it's definitely safe to say this is a rendering bug specific to something about my device. Perhaps there's some underlying difference in how the browser renders things as a response to a touch vs. when the scroll position is programmatically manipulated (as with a snap). Interestingly, though, on said (problematic) device — the scrollbar seems to sometimes not show at all with the new betas (noticed with the new scrollTrigger by itself and with both scrollTrigger + scrollSmoother). I'm able to scroll normally in any event, but occasionally the page loads entirely without a scroll bar. It seems intermittent as far as I can tell, but is most easily replicable after clearing my cache and returning to the demo after some time. In any event, thank you so much for tracking down a remedy for this! I'm eager to see the next version address it. In my situation, though, I may re-work things to use native sticky positioning and just use the scroll trigger to scrub the timeline and not worry about pinning. Since, in practice, there's only one full-screen element like this on the page, it may be worth carving out the exception to handle it. 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now