Jump to content
GreenSock

s94QREspJB

ScrollTrigger in iOS

Recommended Posts

Hi all,


we recently did a project with a scroll trigger that creates an endless scroll behaviour. See attached codepen for the markup. Therefore, we need the callbacks of onLeave and onLeaveBack to trigger immediately, also while scrolling: as soon as its marker is hit, the scroll position is updated to either top or bottom 0 values. It works fine on all desktop browsers but not in Safari. It kinda "waits" until the scroll is finished and only then navigates.

This means the scrolling stops for a sec, updates the values and then the user has to start scrolling again. Ideally, this should be one fluid motion. Did anyone ever encounter this issue and knows some way to fix this? We think it might be Safari's easing of the scroll that interferes. I'm not sure if you guys can see this in the CodePen example cuz this seems to work just fine. We think this is due to the fact that the interface does not change when scrolling is happening, e.g browser bar moves in and out. So here is the production website https://dev.mensingtimofticiuc.com as well.

 

Thankful for any hints or tipps and thanks in advance!

See the Pen ZEaXrKx by spar-nation-alleluia (@spar-nation-alleluia) on CodePen

Link to comment
Share on other sites

15 hours ago, s94QREspJB said:

Did anyone ever encounter this issue and knows some way to fix this? We think it might be Safari's easing of the scroll that interferes. I'm not sure if you guys can see this in the CodePen example cuz this seems to work just fine. We think this is due to the fact that the interface does not change when scrolling is happening, e.g browser bar moves in and out.

 

Safari is just a super difficult browser to work with, and there probably isn't a good solution. We spent several weeks trying to solve issues dealing with the address bar on iPhones and couldn't find a way to prevent it from resizing. iPads isn't an issue, just iPhones. 

 

Link to comment
Share on other sites

3 hours ago, OSUblake said:

 

Safari is just a super difficult browser to work with, and there probably isn't a good solution. We spent several weeks trying to solve issues dealing with the address bar on iPhones and couldn't find a way to prevent it from resizing. iPads isn't an issue, just iPhones. 

 

Yeah, that's so. We found some workarounds, though. What we did was to set the height of the html and body elements to 100% and prevent the body element from overflowing. Then, instead set its child (or the one with all your content) to overflow: auto and also set it's height to 100%. This way, you can prevent the address bar from moving in and out. There are some other articles on that topic that I discovered in the forum here. I will link that here just in case they could help someone. First, there is CSS Tricks with an overview and then Matt Smith with a WebKit solution.

Not tested though but will do that now since we encountered another issue: the markers of the trigger scroller-start and scroller-end, seem to react to the actual scrolling. They flicker and move up and down quickly by about 50px or so. This might be the reason for why the scroller does not work reliably on mobile browsers (issue encountered on all mobile browsers). Maybe that's just due to the way I implemented this. Will keep this thread updated, though.

Link to comment
Share on other sites

6 minutes ago, s94QREspJB said:

We found some workarounds, though. What we did was to set the height of the html and body elements to 100% and prevent the body element from overflowing. Then, instead set its child (or the one with all your content) to overflow: auto and also set it's height to 100%. This way, you can prevent the address bar from moving in and out.

 

Yeah, we looked at that too, but we can't use a nested scroller for what we're doing. You'll see in the next release of GSAP, which has a lot of new scrolling features and improvements. Stay tuned 😉

 

Link to comment
Share on other sites

Update: after implementing and testing the code suggested in the articles above it seems again that only setting the body element to overflow: hidden and it's child to overflow: auto (as described in my post above) helps to prevent viewport height changes. This can't be the solution, though, because the markers flicker in their position and are not fixed as you would expect it from desktop experiences. Is there something that can be done here? See the screen cast on iOS 15.3.1 on Safari here: https://drive.protonmail.com/urls/YMTBPAXHZW#tLm15WgQq1QO

Additionally, if none of the options described in this thread are applied, the scroll trigger does resize but only once the user has finished scrolling. This does not work reliably as it should happen immediately after the viewport changes. Is there some option or function to tell the scroll trigger to resize immediately rather than waiting for the scroll to finish? See the screen cast for this issue on iOS 15.3.1 on Safari here: https://drive.protonmail.com/urls/A1FCWDTY44#qyesN99JRMP3

 

The code is in both cases the same as in the OP, instead of changing the scroller for option 1 to the overflowing child container like so (done with Vue.js v2.6.12):

 

this.scroller = document.getElementById('scroller');
createScrollTrigger() {
// ...
this.scrollTrigger = ScrollTrigger.create({
scroller: `#scroller`,
// ...
},

Pen posted again here for the sake of completion:

See the Pen ZEaXrKx by spar-nation-alleluia (@spar-nation-alleluia) on CodePen

 

Greatly appreciating any help and thanks in advance!

Link to comment
Share on other sites

20 hours ago, s94QREspJB said:

the markers flicker in their position and are not fixed as you would expect it from desktop experiences. Is there something that can be done here?

iOS Safari has quite a few glaring bugs related to scrolling.

 

You might want to look into the brand new ScrollTrigger.normalizeScroll() as well as the new:

ScrollTrigger.config({ ignoreMobileResize: true });

And try the new 3.10.0. See if it improves anything for you, especially by activating the normalizeScroll() feature.

 

Markers are only for during development anyway, so I wouldn't worry too much if they jitter since you'll remove them.

 

20 hours ago, s94QREspJB said:

Additionally, if none of the options described in this thread are applied, the scroll trigger does resize but only once the user has finished scrolling. This does not work reliably as it should happen immediately after the viewport changes

This was very intentional, actually. If the ScrollTrigger.refresh() occurs during the momentum scroll, it'll suddenly stop it. Not because ScrollTrigger is asking it to, but because if there's any setting of the scroll position whatsoever, the browser assumes it should stop. Therefore, we specifically added code to wait until the momentum scroll is done before triggering the refresh(). So it's a feature, not a bug :)

 

You can definitely force a ScrollTrigger.refresh() anytime you want. Like in a "resize" event handler. You can also use ScrollTrigger.config() to have ScrollTrigger not refresh() automatically on window resizes at all if you prefer to handle that on your own (change autoRefreshEvents). It's super flexible.  

 

Does that help at all? 

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

Hello there!

 

Quote

And try the new 3.10.0. See if it improves anything for you, especially by activating the normalizeScroll() feature.

 I tried this but unfortunately, it does not fix our problem. Resizing due to the address bar transitioning in and out still takes place. In my understanding, normalizeScroll() is a method you'd use on the whole instance of your Scroll Trigger, therefore I placed it beaneath the actual initialization. Not sure if it does something now. Also, if I store the instance in a variable and use it like so this.scrollTrigger.normalizeScroll(), it's throwing an error saying that normalizeScroll() is not a function. Does this only work globally on all instances?


If this implementation is correct, the problem could still persist due due to the fact that we're on the latest iOS which was pointed out to not work with normalizeScroll(). Seen in the docs with:

Quote

One exception we know of is the most recent version of iOS, only on phones in portrait orientation where the browser forces the show/hide (it seems impossible to work around, but you can still use ScrollTrigger.config({ ignoreMobileResize: true}) to skip refreshes in that case). 


I then tried ignoreResize: true as a config parameter which also does not seem to change anything. In the updated pen attached, you will find the way I implemented both methods. Might be that I missed something.
 

See the Pen ZEaXrKx by spar-nation-alleluia (@spar-nation-alleluia) on CodePen

 

Due to these (to me) unresolvable issues, I reverted back to the code to make it at least work. I found that on mobile, the trigger does not work at all anymore. Pen reflects current code. Does anyone know why this is the case? In CodePen, it does work just fine. This is the link to the screen capture of the live project to help you understand the problem: https://drive.protonmail.com/urls/3W8WQVTPXM#GcTSjdGcPQkv

 

Thanks for your help guys and have a nice day!

Link to comment
Share on other sites

On 4/6/2022 at 1:55 AM, s94QREspJB said:

normalizeScroll() is a method you'd use on the whole instance of your Scroll Trigger, therefore I placed it beaneath the actual initialization. Not sure if it does something now. Also, if I store the instance in a variable and use it like so this.scrollTrigger.normalizeScroll(), it's throwing an error saying that normalizeScroll() is not a function. Does this only work globally on all instances?

Yes, you just call the static ScrollTrigger.normalizeScroll(true) function and it applies special behavior to the scrolling of the root/body only. It is NOT a per-ScrollTrigger instance setting. 

 

Your CodePen breaks because you're using an old version of ScrollTrigger that doesn't have normalizeScroll() :)  You need to use the latest version (3.10.2 as of right now). I bet that's why you didn't notice any difference with this line too: 

ScrollTrigger.config({ ignoreMobileResize: true });

That won't do anything if you're not using 3.10.x+

 

Side note: I noticed you're setting syncInterval: 999999999 on the ScrollTrigger.create() config, but that won't do anything. That's a ScrollTrigger.config() setting that's global. Again, it won't hurt anything to have it where you do - it simply gets ignored. 

 

Lastly, I looked at your demo on my iPad and I didn't notice any strange behavior at all - what are the symptoms I should be looking for? How exactly is it breaking? Does it only happen on iPhones? Does it work again if you revert to 3.9.0? 

  • Thanks 1
Link to comment
Share on other sites

  • 2 weeks later...

Alright, thx for clarifying!

I did disable the syncInterval now as it did not seem to make any difference, even with the correct implementation. normalizeScroll() set globally did stop the scrolling from working. The user could not scroll at all. I was unable to find out why this is the case. If it matters: we are developing on Vue.js v.2.6. Might be that the threading is mixed up somehow? :huh:


Oh, sure! I did not use the latest version of GSAP in the Pen but have the latest as of now in use in my project. We did change the code to make it work again. Therefore we removed the conditions with isLopping int he callbacks. If I do this in the pen, it stops working however because then both triggers are called at the same time. In (most) of the browsers, it works fine, though.

 

Quote

Lastly, I looked at your demo on my iPad and I didn't notice any strange behavior at all - what are the symptoms I should be looking for? How exactly is it breaking? Does it only happen on iPhones? Does it work again if you revert to 3.9.0? 

Did you look at the pen on your iPad or the actual link of the project I provided? If it was the latter, could you try it again now that we've updated the code? It works fine but sporadically stops scrolling as it reaches top or bottom of the page. It should, just as before keep on scrolling due to the endless scroll we implemented. It happens on all mobile browsers and also on iOS as well as Android (at least that's what I tested with browserstack) and the GSAP version does not matter. It happens all the same.

 

Here's the link of the project again and this is a screen cast of what I mean.

Link to comment
Share on other sites

I suspect the non-infinite scroll issue is caused by the fact that you're setting the start/end to the VERY top and bottom which doesn't always let it actually hit or exceed - I would use a 1 pixel threshold like: 

start: 1,
end: () => ScrollTrigger.maxScroll(window) - 1,

Some browsers report scrolling values as very slightly off, thus you're giving yourself a little wiggle room to cover over those inconsistencies. 

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