Jump to content
Search Community

ScrollTrigger Snap + Smooth Scroll causes odd behavior

SteveS test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

Note: I'm seeing the codepens linked are incorrectly positioned in the post. The one with peaches is ASScroll, the other is smooth-scrollbar

 

When using some smooth scroll libraries through ScrollerProxy(), if a scrolltrigger has both `scrub: true` and `snap: 1`, instead of snapping back to the nearest position, the page does different things.

 

ASScroll
I originally found this when trying to use ASScroll. With ASScroll, the effect is that the page animates several pixels at a time back to one of the snap points. The only change made in this codepen is the addition of `snap: 1`

 

Locomotive Scroll

Acts similarly if not exactly the same as ASScroll. I would have provided a demo, but for whatever reason CodePen won't let me fork the official GSAP demo. Again, simply adding `snap: 1` will show the behavior.

Smooth-Scrollbar

Interestingly, snap appears to work as expected with this library.

See the Pen xxqqwdQ by SteveSDaBest (@SteveSDaBest) on CodePen

 

Having looked through the documentation for ScrollTrigger, I can't seem to find a setting, option or configuration which doesn't produce this result in ASScroll. Anyone have any ideas for workarounds or solutions?

See the Pen NWppGdb by SteveSDaBest (@SteveSDaBest) on CodePen

Link to comment
Share on other sites

  • Solution

We don't really support 3rd party libraries like ASScroll, LocomotiveScroll, etc. but it looks like the issue had to do with the fact that the scrollerProxy's setter was using asscroll.scrollTo(value) instead of asscroll.currentPos = value which employed smooth scrolling thereby bouncing back and forth where it would smooth scroll, update, try to smooth scroll to the new position, and so on. It's a logic issue. I made some improvements to the demo that we link to on the scrollerProxy() docs page. Here's a fork with the scrub: 1 set:

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

 

Does that clear things up? 

 

You could also consider using the native ScrollTrigger helper function (no 3rd party libraries necessary) as linked to on the scrollerProxy() docs page. 👍

  • Like 1
Link to comment
Share on other sites

Yep, I actually figured this out right after posting. I have considered using the native GSAP smooth scroll, but there are some features of ASScroll which make it my go to. I've communicated with the creator of the library and he's updated the demo to correctly work with snap. Thanks!

  • Thanks 1
Link to comment
Share on other sites

8 hours ago, SteveS said:

I have considered using the native GSAP smooth scroll, but there are some features of ASScroll which make it my go to.

Would you mind elaborating a bit? What features exactly? 

 

I'm not against ASScroll or any other third party library at all - this is just me being curious. 

Link to comment
Share on other sites

I can scroll while my mouse is over iframes and I can use middle mouse scroll, where you click in the middle mouse and drag. These two features seem to be exclusive to ASScroll. On top of that, the configuration is simple compared to the GSAP method, I really know what to expect when I use the library. The downside of course is I don't have as granular of control compared to a gsap method, but for most cases it's a really nice solution.

Link to comment
Share on other sites

4 minutes ago, SteveS said:

I can scroll while my mouse is over iframes

Are you saying that you want to scroll the outer page instead of the iframe content when your mouse is over an iframe? Or the other way around? 

 

5 minutes ago, SteveS said:

I can use middle mouse scroll, where you click in the middle mouse and drag

I've never heard of that or experienced it. Hm. Like...you click on the middle button of a 3-button mouse and then drag and that drag-scrolls? 

 

6 minutes ago, SteveS said:

the configuration is simple compared to the GSAP method

Well that just baffles me. I didn't think it could possibly get any easier than:

smoothScroll("#content");

🤔

Link to comment
Share on other sites

10 hours ago, GreenSock said:

Are you saying that you want to scroll the outer page instead of the iframe content when your mouse is over an iframe? Or the other way around?

While I haven't tested it with the native GSAP smooth scroll, most all implementations of smooth scroll will stop in its tracks once your mouse goes over an iframe or even embedded content. ASScroll doesn't have that problem as far as I can tell.

 

10 hours ago, GreenSock said:

I've never heard of that or experienced it. Hm. Like...you click on the middle button of a 3-button mouse and then drag and that drag-scrolls? 

Maybe? When I click (not click and hold) my middle mouse button in on a web page I am able to scroll the page by moving my mouse up in down. I use this frequently to quickly scroll through webpages, and when I am on websites that don't let me do it, it is incredibly frustrating and a complete deal breaker. ASScroll has been the only library I've tried which doesn't prevent me from using this type of scroll.

As for ease of use, I guess I mean more settings and properties that I can tweak on the fly, as well as various methods that I can then use for ThreeJS animations and other complex interactions. I'm sure it's possible to do that with the helper function provided in the ScrollerProxy examples, but the documentation isn't exactly robust, so while I lose some freedom by using a separate library, I also have a bit more control over the scrolling in a general sense. If GSAP came out with a smooth scroll library plugin which had more robust documentation and features, I'd seriously consider switching to it.

Link to comment
Share on other sites

11 hours ago, SteveS said:

most all implementations of smooth scroll will stop in its tracks once your mouse goes over an iframe or even embedded content.

Isn't that what would be considered "normal" behavior for browsers? Like...if I'm scrolling down a page and my mouse gets to an iframe that's scrollable, the browser will typically scroll the iframe at that point. Are you saying you prefer non-standard behavior where iframes are ignored? Or did I misunderstand? 

 

11 hours ago, SteveS said:

I mean more settings and properties that I can tweak on the fly, as well as various methods that I can then use for ThreeJS animations and other complex interactions.

It'd be super cool if you could elaborate a bit on what "settings and properties" you find particularly useful. 

  • Like 1
Link to comment
Share on other sites

6 hours ago, GreenSock said:

Are you saying you prefer non-standard behavior where iframes are ignored? Or did I misunderstand?

The particular use case I'm thinking of is having an embedded twitch stream, a non-scrollable element which halts the scroll input entirely. While I haven't tested it with the GSAP helper for SS, I imagine it would yield similar results as other smooth scroll libraries.

 

6 hours ago, GreenSock said:

It'd be super cool if you could elaborate a bit on what "settings and properties" you find particularly useful. 

Because of the way ASScroll has it's documentation laid out, I understand how to easily access position getters/setters, velocity, lerp rate, resize, etc. It's difficult to make a direct comparison since the GSAP way doesn't have documentation at all. Having an array of methods to interpret scroll related data with makes it generally easier to create linked animations in THREEjs. If I'm looking to accomplish something, I can look at the docs for ASScroll and figure out if there's an option there.

I guess one example is hooking up RellaxJS, a parallax scroll library, to work with smooth scroll. Of course there is a native gsap way to do that as well, but I'd consider myself pretty new to gsap generally so I don't have the know-how to make that all happen yet. Anyway, Rellax requires a scroll element to look at and get the scroll position from, so I set up asscroll to also set the scroll position of an invisible element of equal height to the window and had rellaxJS look at that. Maybe not a great example, but at the very least I could start at the documentation of each library and piece it together.

That being said I do have some improvements I would like to see with ASScroll. Naming conventions of properties aren't exactly intuitive, and sometimes the library has weird behavior which I am working through. Overall though, it seems to have the most native feeling scroll experience while still being smooth.

  • Like 1
Link to comment
Share on other sites

Here's a fork with a YouTube video dropped into an iframe - I don't notice any odd behavior when scrolling over it, do you? 

See the Pen xxqdyqO?editors=1010 by GreenSock (@GreenSock) on CodePen

 

Regarding docs, I guess I see what you mean but really everything is based on ScrollTrigger anyway which is very thoroughly documented. So the helper function is only intended to add some smooth scrolling capabilities, and you can tweak how long it takes to "catch up" to the real scroll position. That's about it - I'm not quite sure what else you'd need. 

 

If you want to scroll to a particular position, that's the .scroll() method. Pinning and animating and all that fun stuff is no different - it's all very standard ScrollTrigger stuff. 

 

Again, my goal isn't to convince you to use the helper function or to imply that ASScroll is inferior in any way. I was just being curious so that I can better understand what users like yourself care about and how you make decisions. 

 

Happy scrolling!

  • Like 2
Link to comment
Share on other sites

16 hours ago, GreenSock said:

Here's a fork with a YouTube video dropped into an iframe - I don't notice any odd behavior when scrolling over it, do you?

Huh, I also tested this with the locomotive-scroll example. Using the locomotive scroll library, the scroller stops in its tracks, but when I use the gsap helper function, it works perfectly.

 

Example of issue using locomotive-scroll:

See the Pen RwpgRvz by SteveSDaBest (@SteveSDaBest) on CodePen


I shouldn't have assumed it wouldn't work. Maybe I'll take a closer look at a native GSAP solution, though middle mouse click to scroll is definitely still a dealbreaker for me, perhaps there is a solution to that.

In playing around with it, I did also notice that the ScrollTrigger markers don't line up with the scrolling content, but I'm sure that's a configuration of the scrollerProxy.

Link to comment
Share on other sites

3 hours ago, SteveS said:

Huh, I also tested this with the locomotive-scroll example. Using the locomotive scroll library, the scroller stops in its tracks, but when I use the gsap helper function, it works perfectly.

Yep, I see what you mean. I'm not very familiar with LocomotiveScroll or why it's behaving that way, but I definitely think it's problematic. Unrelated to ScrollTrigger/GSAP.

 

3 hours ago, SteveS said:

though middle mouse click to scroll is definitely still a dealbreaker for me, perhaps there is a solution to that.

I'm on a Mac and don't have a mouse like that, but are you saying that the GSAP helper function doesn't work the way you'd want? Again, it is using the native scroll functionality of the browser, so I'd be a bit surprised if you're saying that you CAN scroll normal web pages that way but NOT the one with the GSAP helper function. Can you confirm that's what you mean? 

 

3 hours ago, SteveS said:

In playing around with it, I did also notice that the ScrollTrigger markers don't line up with the scrolling content, but I'm sure that's a configuration of the scrollerProxy.

Are you talking about the LocomotiveScroll one? Yeah, that's due to issues with the way LocomotiveScroll handles things. The ScrollTrigger native one seems to work fine for me, although there was an issue in past versions that could cause the markers to have display: none but that's fixed in the upcoming release which you can preview (compressed) at https://assets.codepen.io/16327/ScrollTrigger.min.js

Link to comment
Share on other sites

36 minutes ago, GreenSock said:

Yep, I see what you mean. I'm not very familiar with LocomotiveScroll or why it's behaving that way, but I definitely think it's problematic. Unrelated to ScrollTrigger/GSAP.

My understanding is that this is a common issue with smooth-scroll libraries, nothing to do with GSAP.

 

 

30 minutes ago, GreenSock said:

I'm on a Mac and don't have a mouse like that, but are you saying that the GSAP helper function doesn't work the way you'd want? Again, it is using the native scroll functionality of the browser, so I'd be a bit surprised if you're saying that you CAN scroll normal web pages that way but NOT the one with the GSAP helper function. Can you confirm that's what you mean?

Here is an example of the interaction, you'll have to excuse the slightly broken page.

https://gyazo.com/3a4a1ae071bbb6bd80d02b9a72c13ec3

 

Interestingly, I just found out that while smooth-scrollbar and LocomotiveScroll are unable to make use of this kind of scrolling at all, ASScroll and native GSAP scroll both work in Google Chrome. The native GSAP method doesn't permit this kind of scrolling in Firefox Developer Edition (I haven't tested regular FF, but I imagine it's the same) when in CodePen. However, I just tested it with a site running locally on my machine, and it DOES work in Firefox.

I guess I never sat down and really tested everything side-by-side on a local development site. I guess the Firefox implementation of native scroll doesn't interact well with Codepen compared to chrome, and for whatever reason, the ASScroll method of doing things worked across the board for me.

Without some extra testing with regards to mobile and ThreeJS, I can't say for sure I'm able to move over to the native GSAP method, but I'm very interested in exploring it as an option now that I see it does in fact work for the Middle mouse click to scroll interaction. It would definitely be nice to have it work straight from gsap instead of bringing in another library.

 

  • Thanks 1
Link to comment
Share on other sites

10 minutes ago, SteveS said:

Interestingly, I just found out that while smooth-scrollbar and LocomotiveScroll are unable to make use of this kind of scrolling at all, ASScroll and native GSAP scroll both work in Google Chrome. The native GSAP method doesn't permit this kind of scrolling in Firefox Developer Edition (I haven't tested regular FF, but I imagine it's the same) when in CodePen. However, I just tested it with a site running locally on my machine, and it DOES work in Firefox.

Thanks for confirming. Very happy to hear that the native GSAP one worked well in all cases except inside CodePen. I know that CodePen does some funky stuff in their environment with iframes and disabling certain things. 

 

12 minutes ago, SteveS said:

I'm very interested in exploring it as an option now that I see it does in fact work for the Middle mouse click to scroll interaction. It would definitely be nice to have it work straight from gsap instead of bringing in another library.

🎉

 

Again, my goal wasn't to imply it's "bad" to use ASScroll or anything like that. But obviously I invested some time in that helper function that has some unique benefits of its own. 

 

Let us know if you come across any other nuggets that we should keep in mind. 

 

Good luck!

Link to comment
Share on other sites

Hey, I'm the author of ASScroll so just thought I'd chime in here :)

 

Just for clarification - the iframe issue is that once your mouse enters an iframe, the `wheel` event on the parent window stops firing since it's not linked to any sort of overscroll behaviour. It won't fire until your mouse leaves the iframe again, which is problematic especially on trackpads since the mouse will sort of stay in the same position as you try and continue to scroll past with two fingers.

 

The reason ASScroll works in those edge cases like when hovering over an iframe or using the middle mouse button to scroll, is the same reason the GSAP smooth scroll implementation also works (as far as I can see).

 

The GSAP version looks like it listens to the `scroll` window event and updates the transform accordingly. I would say that it exclusively listens to this event since I can see the native scrollbar matching the smoothed scroll position exactly, but I can also see some `wheel` events so it may be using a combination, like ASScroll.

 

Using the native scroll position like this means that you're just extending the scroll functionality rather than overriding it, which is what the other smooth scroll libraries do, like Locomotive and smooth-scrollbar. They exclusively listen to the `wheel` event, so they need to essentially rebuild the entire native scroll functionality again. This means they use arbitrary values for when they manually recreate keyboard scrolling (arrow keys, pg up/down, home/end etc.) which won't match the scroll speed the user has defined in their OS - this also introduces a whole host of issues like now having to deal with keypresses when in an input field, for example. And they will never be able to deal with the iframe issue unless they also listen to the `scroll` event.

 

So I think the difference between the GSAP smooth scroll implementation and ASScroll, is that ASScroll uses a hybrid setup - `wheel` if its available to provide the high-performance 'virtual scroll' setup, and `scroll` if `wheel` isn't available for whatever reason - like keyboard navigation, hovering an iframe, using a screen reader etc.

 

I'd be curious to see how the GSAP version handles syncing DOM with WebGL for example, which nowadays is the primary requirement for having to use 'virtual scroll' since listening to `window.scrollY/pageYOffset` causes lag between the two.

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

Indeed, thanks for chiming in, @ashthornton

 

3 hours ago, ashthornton said:

I'd be curious to see how the GSAP version handles syncing DOM with WebGL for example, which nowadays is the primary requirement for having to use 'virtual scroll' since listening to `window.scrollY/pageYOffset` causes lag between the two.

I didn't quite follow that - are you saying that listening to "scroll" events and responding on requestAnimationFrame() actually causes lag somehow? Got any demos or other data that'd illustrate that? And does ASScroll do something special to accommodate it? 

Link to comment
Share on other sites

21 minutes ago, GreenSock said:

I didn't quite follow that - are you saying that listening to "scroll" events and responding on requestAnimationFrame() actually causes lag somehow? Got any demos or other data that'd illustrate that? And does ASScroll do something special to accommodate it? 

 

I meant that using window.scrollY/pageYOffset to set positions of objects in WebGL causes a lag between DOM and WebGL position.

 

I've just replaced ASScroll with your smooth scroll implementation on my basic DOM/WebGL sync demo and it does seem to work perfectly fine without any lag. And having looked through the ScrollTrigger source code, it does seem to end up just using window.pageYOffset. This is interesting! Codepen here: 

See the Pen 874833fdebc032bedd0cf61e9eac3ee9 by ashthornton (@ashthornton) on CodePen

 

The idea behind performant smooth scroll has always been to create a 'virtual scroll' using the wheel delta to set the scroll position, since reading window.pageYOffset causes the browser to layout so its an expensive property to access in a requestAnimationFrame loop and then translate an element based on that.

 

Looks like I have some investigating to do :) 

  • Like 1
Link to comment
Share on other sites

Well I guess that's good news! Thanks for digging into that and even providing a demo. 

 

If I understand correctly, accessing pageYOffset is only expensive if things have been changed/invalidated. If you know of a better way to do things, I'm all ears, of course. But I really want to avoid wandering too far from native scroll functionality. 

  • Like 1
Link to comment
Share on other sites

  • 1 year later...
On 5/22/2021 at 3:24 AM, GreenSock said:

We don't really support 3rd party libraries like ASScroll, LocomotiveScroll, etc. but it looks like the issue had to do with the fact that the scrollerProxy's setter was using asscroll.scrollTo(value) instead of asscroll.currentPos = value which employed smooth scrolling thereby bouncing back and forth where it would smooth scroll, update, try to smooth scroll to the new position, and so on. It's a logic issue. I made some improvements to the demo that we link to on the scrollerProxy() docs page. Here's a fork with the scrub: 1 set:

 

 

 

Does that clear things up? 

 

You could also consider using the native ScrollTrigger helper function (no 3rd party libraries necessary) as linked to on the scrollerProxy() docs page. 👍

How do you get setupASScroll()

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