Jump to content
Search Community

Persistent Issue with GSAP Scroll Trigger on iPhone in battery save mode

Kopp001 test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

Hello GSAP Community,

 

I'm reaching out to share and seek guidance on a specific issue I've encountered with the Scroll Trigger in GSAP, particularly on mobile devices.

 

Device and Context:

  • Device: iPhone 15 Pro
  • Operating Mode: Battery Power Save Mode

Issue Description:
While using my iPhone in Battery Power Save Mode, I experience a consistent and disruptive issue on all websites that use GSAP's Scroll Trigger. The issue manifests as an intermittent interruption of the scrolling motion, resulting in a jarring and "janky" user experience. This occurs every two to three scrolls, where a smooth scrolling motion is abruptly halted.

 

Key Observations:

This issue seems exclusive to GSAP's Scroll Trigger. I have not observed similar behavior with other scrolling animation libraries like anime.js or with native JavaScript Intersection Observers.
The problem persists across all websites employing GSAP's Scroll Trigger, suggesting it's not related to a specific implementation error on my part.


Purpose of This Post:

To determine if this is a known issue with GSAP, especially in the context of mobile devices operating in power-saving modes.
To inquire if others in the community have faced similar challenges and, if so, how they addressed them.


To seek potential solutions or workarounds that ensure smoother scroll-triggered animations in power-saving modes.
Attached Material:

Enclosed is a video demonstrating this issue, using the official GSAP website as an example. This should provide a clear illustration of the janky scrolling behavior I've been experiencing.

 

I am looking forward to any insights, suggestions, or shared experiences regarding this matter. Understanding whether this is a recognized limitation within GSAP or an external factor related to device-specific functionalities would be immensely helpful.

 

Thank you in advance for your time and assistance.

 

Kevin

Link to comment
Share on other sites

Hi there,

 

So as you mentioned, this The iPhone screen usually has a refresh rate of 60Hz, but in Low Power Mode that rate is reduced to around 30Hz to save battery power. I notice this impact on scroll in general, so I'm not really surprised that scroll animations are impacted.

 

I doubt this is a GSAP specific thing, but I would guess this affects animations that are 'scrubbed' by the scroll position more. Which is a very common ScrollTrigger pattern.

 


It's unfortunate there's not a media query for low power mode because ideally we could just switch off animations, much like with the prefers reduced motion query. 

 

Link to comment
Share on other sites

Interestingly (or annoyingly depending on perspective) I just tested on my phone and the gsap site homepage and our scroll animation page are both working perfectly for me, a little frame jitter, but nothing too noticeable, definitely no page stalling.

 

I haven't used low battery mode in quite a while, so maybe my original observation isn't quite accurate? Or maybe it only applies to devices with both power saving on and low battery? 

Link to comment
Share on other sites

Hi Cassie,

Noted on the refresh rate drop in Low Power Mode. I've seen the same scrolling hiccups on an Android device in power save mode as well. The interruptions aren't consistent - sometimes it happens after a single scroll, other times it might take five or more.

 

On my site, I use GSAP's Scroll Trigger for basic class toggling—no scrubbing, just simple onEnter and onLeave callbacks. Yet, the mere presence of Scroll Trigger seems to be enough to cause these random scrolling stops.

 

 

I've started to notice this issue on any site that uses Scroll Trigger. It's like once you see it, you can't unsee it. Especially since I've been trying to replicate the issue by intentionally scrolling fast to test it out.

 

It's a pesky problem, considering other libraries don't cause the same behavior. Definitely seems tied to GSAP's Scroll Trigger when in power save mode. Not a deal-breaker, but it's annoying and throws off the smoothness we're all aiming for.

 

 

Any ideas why this might be happening or ways to work around it?

Link to comment
Share on other sites

  • Solution

Oh, I wonder if you're just talking about the "jump" caused by the address bar showing/hiding which alters the viewport size and therefore all of the intersection points for the various ScrollTriggers, thus they get recalculated as soon as scrolling stops (we intentionally wait for the scrolling to stop so that it doesn't interfere with the momentum scroll). You can tell ScrollTrigger to skip that refresh completely if you'd like: 

ScrollTrigger.config({ ignoreMobileResize: true });

Does that resolve things for you? 

 

I'm also curious if this helps at all:

ScrollTrigger.normalizeScroll(true);

 

Are you noticing that "jank" you mentioned when you **only** scroll in one direction **after** the address bar shows/hides? I'm trying to ascertain if  what you're describing is purely related to the viewport resizing or not. 

 

Thanks for the clear, organized way you posted about the problem. Sorry about the frustrations!

Link to comment
Share on other sites

Hi !

Just gave the ignoreMobileResize config a shot, and it worked like a charm – no more scroll interruptions. It seems like the issue was indeed tied to the Safari toolbar appearing and disappearing. This fix nailed it, so thank you for that!

 

On the flip side, normalizeScroll(true) just threw things off, making scrolling on iOS pretty much a no-go.

 

 

With the ignoreMobileResize solution in place, I'm curious about the potential downsides. If it's such an effective fix, I'm wondering why it's not a default setting, or if there's any trade-off I'm not seeing. Could this be the silver bullet for the scroll issue, or is there a catch?

 

Seriously, big thanks for the prompt and effective solution. It’s a huge relief.

Link to comment
Share on other sites

19 minutes ago, Kopp001 said:

With the ignoreMobileResize solution in place, I'm curious about the potential downsides. If it's such an effective fix, I'm wondering why it's not a default setting, or if there's any trade-off I'm not seeing. Could this be the silver bullet for the scroll issue, or is there a catch?

Let's say the viewport is 1000px and the address bar is 200px. So when you load the page and the address bar is showing, there's 800px of space. You've got a <div> that sits 1100px down from the very top of the viewport and let's say you've got a ScrollTrigger set up on that so that when it hits the bottom of the viewport (entering), it fires. That means that you'd have to scroll 300px before that should fire originally (800px visible viewport area + 300px scroll = 1100px from the top). Now you start scrolling and the address bar hides. Doh! Now the viewport is 1000px tall which means you'd only have to scroll 100px before that <div> enters the viewport. See the problem? ScrollTrigger prioritizes accuracy for all the intersection points - that's why it has to do a .refresh() when the window resizes. And it automatically debounces for performance reasons so that it's not constantly doing a bunch of refreshes as the address bar animates in/out. 

 

So the tradeoff is accuracy of the trigger position calculations. Practically-speaking, though, most people probably don't care much and would rather avoid the brief interruption caused by the refresh() calculations, hence the ScrollTrigger.config({ ignoreMobileResize: true }) option. The reason we didn't make that the default, though, is because it felt pretty weird to intentionally choose inaccuracy. We didn't want forums posts saying "why are my ScrollTriggers inaccurate??" - we'd rather people opt-in to the ignoreMobileResize behavior, knowing full well that it may lead to intersection points being inaccurate. Which, again, in most cases I'd guess is functionally fine for people. It's not as if everything would look horribly broken if a ScrollTrigger fires 140px further down on the page than they might expect. 🤷‍♂️ However, in certain layouts it could DEFINITELY be problematic.

 

Ultimately it's a logic challenge related to the viewport resizing. It's not a bug. And even the "jump" that you might see is logically necessary for things to be accurate - it's not a glitch. See what I mean? 

 

Does that clear things up? 

Link to comment
Share on other sites

31 minutes ago, Kopp001 said:

On the flip side, normalizeScroll(true) just threw things off, making scrolling on iOS pretty much a no-go.

It's not a silver bullet. iOS has a bunch of major scroll-related bugs, some of which have existed for years. It's quite shocking to me, actually. We've reached out to the Safari team on many occasions and largely all we get are the sounds of crickets chirping. 

 

The normalizeScroll() feature aims to solve the problem of Safari using a separate thread for scrolling that isn't synchronized with the main thread. So, for example, imagine that you scroll really fast and you've got a <div> that should pin when it hits the top of the screen; Maybe that scroll event moved the page 100px. Safari would just render that page as if the whole thing moved up 100px...and then eventually it would run the main thread JS where ScrollTrigger says "whoah, that <div> should be pinned...let me do that" and you'd visually see it jump back down to where it should be pinned. It'd look like a glitch/jump. That's not a bug in ScrollTrigger - it's a consequence of Safari doing the scrolling on a separate, non-synchronized thread. To add insult to injury, bugs in iOS TouchEvents cause them to incorrectly report clientY when any scrolling has occurred recently! So you can't even discern where a person's finger is on the screen to determine proper scroll position as a workaround. It's incredible how much work we put into trying to solve all these challenges (literally hundreds and hundreds of hours were sunk into this). Currently, the normalizeScroll() feature has to implement some wild stuff to interpolate every-other TouchEvent position, applying a transform: translateY() on every-other movement to attempt to smooth things out. But like I said, it's not a silver bullet. It can't work miracles. It does, however, solve a jittering issue. If you could see a before/after of what I'm describing, I think you'd be impressed actually. :)

 

Anyway, I'm glad the ignoreMobileResize: true thing helped! 

Link to comment
Share on other sites

Thanks for the detailed explanation – it's super helpful. I'm trying to wrap my head around the mechanics of it, though. I've set up a simple scroll trigger in a CodePen

See the Pen WNmQVvd by saiykoh (@saiykoh) on CodePen

where the trigger is supposed to activate when the top of the element hits 300 pixels from the bottom of the viewport.

 

What's puzzling me is that with ignoreMobileResize set to its default (false), the start marker doesn't seem to move even when the iOS address bar shows or hides. I expected the marker to shift due to the change in viewport height, but it stays put, so I'm not seeing the difference I anticipated.

 

I thought it might be a CodePen iframe quirk, where the address bar doesn't hide on scroll, so I also replicated the test on a standalone site https://gsap-scrolltrigger-test.netlify.app/ to make sure the address bar behaves as it typically would on a regular webpage.

 

Could you help me understand what exactly changes with the ignoreMobileResize set to true? Because from my tests, the behavior seems identical with or without it.

 

 

Thanks again for your patience and the assist here!

 

Link to comment
Share on other sites

Sorry about any confusion there - originally ScrollTrigger based things on window.innerHeight but recently, we switched to a more advanced method that uses 100vh instead which would explain why you're not seeing that shift. Most (if not all) mobile browsers keep 100vh consistent regardless of the address bar showing/hiding. That's the main reason we made that change. 

 

So perhaps we should change the default behavior to ignoreMobileResize: true if it's on a touch-enabled device only. 🤔

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