en en en en en en en en en en en en en en en en en en fa en en fr hbs_lat en en en es en en en ms en de en fr en en en ca en en en en en en en en ms en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en de en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en ms en en en en it en en en nl en es en fr en es en en en en en en en en en en en fr cv es tr es en en en en ms en en en en en en fr en hbs_lat en en en en en en en fr cv es tr es en en en en de en en en ca en en en en en
But I wanted to come up with something that worked on a per-section basis so that I can easily cobble together a patchwork series of bottom layers, top layers, and normal layers. Generally, I try to avoid absolutely positioning elements when possible to help maintain the regular flow of the page.
My question is: Is there anything wrong with this method? Is there a better way to achieve the effect?
There are definitely a few trade-offs doing it my way over the given example. The GSAP is more complex for sure and the nested pin isn't smooth 100% of the time, but I'm not sure the example approach solves that issue regardless. Is there perhaps a better way of getting the effect I'm looking for? It feels a bit hacked together but I'm struggling to find improvements.
See the Pen abYWdVg by SteveSDaBest (@SteveSDaBest) on CodePen
@Cassie I just noticed that when scrolling on desktop (with a mousewheel) the page movement is very staccato. Is this because of normalized scroll? Is there a way to avoid it?
More specifically: I use normalizeScroll because I am using a pinType of transform which, without normalization, is very jittery. I assume that the only solution is ScrollSmoother or normalized scrolling, but if it causes that kind of stutter as I scroll I don't think that this is an acceptable way of getting nested pins.
It seems that "scroll-behavior: smooth" helps but dramatically slows down the scroll speed to the point of being unusable. Not sure what is responsible for that interaction.
Oh fun, more scroll based stuff for @GreenSock to look at - he'll be thrilled. 😂 (Thanks for letting us know though)
See the Pen VwXbKRK?editors=1010 by GreenSock (@GreenSock) on CodePen
It feels like there's always an edge case of some sort with these 'panel' type scroll animations. 🥲
@Cassie So, pinReparent actually does solve the issue by preventing the need of pinType: transform. However, it's just a tad finicky when it transitions into and out of the pin. Like if you scroll fast enough there's a tiny but noticeable snap. I tried looking at ways of taking wheel scroll events and turning them into touch scroll events but that doesn't seem to be 1. a good idea or 2. reasonably possible
There is the negligible issue that reparenting changes the way the CSS needs to be written for the text since removing it from it's section changes the text size. An ideal solution wouldn't require specific practices with CSS for maximum re-usability.
My last alternative is to try and make use of native position:sticky for inner pins. I tried it out a bit when coming up with the method to begin with, but found it cumbersome. However, if it can help avoid these small little issues it might be a good solution.
Alternatively if scroll-behavior worked as expected when combined with normalizedScroll it would also work great. I'm not sure how much I can do in the way of getting that to work, but I'll try to investigate a bit to see if I can come up with something. Usually it's an issue with my code 🙃
SteveS    170 Likes (Specialist)
Okay, so I played around with the potential of using sticky for inner pins and I'm actually quite happy with the results:
See the Pen jOzmVMJ by SteveSDaBest (@SteveSDaBest) on CodePen
I created a small function that is similar to ScrollTrigger pinning except with sticky. Definitely just a proof of concept as shown by the fact that on small screens it doesn't work well, but I can see a polished version being very useful.
That raises the question: why doesn't ScrollTrigger make use of/ have a sticky pin option? I lightly searched for information on the forum but didn't see anything. I feel like it might be slightly less performant, but it feels having the option could save a few headaches.
Share on other sites
SteveS    170 Likes (Specialist)
@GreenSock Do you have any input on this? Perhaps there's a known method for nesting pins that I am not aware of?
Share on other sites
GreenSock    17,226 Likes (Superhero)
Sorry I'm late to the party. Been a bit overwhelmed with a bunch of other stuff. My brain is on low-power mode, so I'm not in a position to fully address this but...
I can't remember all the reasons position: sticky wasn't viable. Some combination of browser support and inability to accomplish certain things. I think it needed the container to be set up a certain way, and it couldn't "hang on" past a certain spot where the container left the viewport...🤷‍♂️ I just know it wasn't feasible.
@SteveS can you provide a very brief summary of what your goal is at this point and what the specific challenge is that you're facing? And the most relevant minimal demo URL?
Share on other sites
SteveS    170 Likes (Specialist)
@GreenSock No real rush.
Goal: Nested pinning of sections that works on desktop.
Nested pins require the internal pin to be of pinType: "transform"
Transform type pins are jittery due to desync between js thread and native scroll thread
Normalizing scroll fixes the jitter, but causes choppy scroll when used with a mousewheel
Using scroll-behavior: smooth and normalized scroll at the same time causes scroll to be extremely slow (bug)
Reparenting the pin prevents the need of a transform pin, but has the tiniest pin of jank when pinning/unpinning and requires CSS to be written differently.
I wrote a rudimentary function to implement sticky scroll that works but is not polished and was wondering why something similar hadn't shipped with ScrollTrigger.
Example of scroll-behavior: smooth and normalized scroll bug:
See the Pen MWVoEjx by StevenStavrakis (@StevenStavrakis) on CodePen
More context below, but not really necessary to get the gist of the issue.
On this website: https://www.apart.agency/
Once you get past the two services section, there is a section that reveals a bottom pin and transfers into a pin on the inner element.
I was trying to construct a way of accomplishing this with absolutely positioning the sections since that dramatically increases the complexity of the effect over being able to handle it only with GSAP.
Share on other sites
GreenSock    17,226 Likes (Superhero)
3 hours ago, SteveS said:
Goal: Nested pinning of sections that works on desktop.
Can you explain what you mean? "Nested" pinning sounds like you want to pin something inside of something that is already pinned, but I'm probably misunderstanding.
3 hours ago, SteveS said:
Using scroll-behavior: smooth and normalized scroll at the same time causes scroll to be extremely slow (bug)
You definitely shouldn't do that. It's not a GSAP bug. Think of it like animating a property that has a CSS transition on it. Every time GSAP sets it to the correct value, the CSS transition will actively prevent that, and say "I'll just gradually set that for you over time"...and then on the very next tick GSAP sets it and the browser interrupts again...and again...it's just horrible for performance. The browser is actively preventing GSAP from doing its job.
Is there any chance you could just isolate a single scenario with as few sections and moving pieces as possible, just to illustrate the challenge you're facing? It can be broken - I just need something like "make the red section pin from the bottom and the blue section pin from the top" (or whatever).
Share on other sites
SteveS    170 Likes (Specialist)
46 minutes ago, GreenSock said:
Is there any chance you could just isolate a single scenario with as few sections and moving pieces as possible
See the Pen ExEXooO by StevenStavrakis (@StevenStavrakis) on CodePen
On my laptop the second "inner" pin is jittery. It's solved by normalizedScroll, but then that causes issues on desktop (choppy scroll).
By nested pin, I mean once the first pin is done, a second inner pin takes effect.
Share on other sites
GreenSock    17,226 Likes (Superhero)
Minor thing: you forgot to set pinnedContainer.
So you're saying that normalizeScroll(true) makes it jittery on your desktop? Gosh, I cannot replicate that at all. Can anyone else? What browser and what system? Any secrets to reproducing?
See the Pen PoRjQKE?editors=1010 by GreenSock (@GreenSock) on CodePen
The reason you must have pinType: "transform" is because once you put an element inside a container that has any transform whatsoever (or will-change), it gets its own stacking context and the browser will refuse to honor the position: fixed on the inner element (well, it won't be fixed to the viewport, it'll be fixed to its container). It's a browser thing.
So knowing this, it may be possible to just structure your HTML/CSS accordingly so that you don't need nested pins. For example, perhaps you put the "inner" part as a sibling and set its margin-top: -100vh, for example. That way it appears visually "inside" but it actually isn't and it doesn't get sucked into the stacking context of its parent.
Share on other sites
SteveS    170 Likes (Specialist)
@GreenSock The hope was to avoid manipulating the DOM from normal if possible to allow the effect to just be drop in. It's super close to 100% working, but it feels like there is just 1 tiny thing in the way no matter how I frame it. Can't imagine the kind of patience an entire library must take 😅
Here is a video of the difference between "choppy" and normal/expected scroll:
Taken of this pen:
See the Pen abYWdVg by StevenStavrakis (@StevenStavrakis) on CodePen
FireFox Developer Edition on Windows 11, but it also appears like this on chrome. When scrolling with a touchpad/touch device this is not an issue.
Share on other sites
GreenSock    17,226 Likes (Superhero)
Oh! I think that's just because on Windows, several browsers automatically apply a kind of subtle scroll smoothing with the wheel. You only see a difference with the wheel, right? Like...if you drag the scrollbar, it's no different?
Obviously normalizeScroll(true) intercepts/prevents the native scroll behavior and handles it via JS. On Windows, wheel jumps are rather abrupt (probably why some browsers impose their own non-standard smoothing). Of course you can use ScrollSmoother to smooth things out.
In short, I don't think this is a bug - it's simply a consequence of Windows browsers imposing their own custom non-standard smoothing to wheel-based scroll updates.
Share on other sites
GreenSock    17,226 Likes (Superhero)
One other thing to try:
ScrollTrigger.normalizeScroll({ wheelSpeed: 0.25 // or whatever value you want });
Does that have any positive effect? Obviously it makes the delta of the wheel 25% of its normal amount.
Share on other sites
SteveS    170 Likes (Specialist)
I agree that that is likely what you are suggesting as when I use the scrollbar/ middle mouse scroll it looks perfectly fine. Really too bad.
15 minutes ago, GreenSock said:
Does that have any positive effect?
Nope. Increases how much I need to scroll but just as choppy.
However, consider that scroll-behavior: smooth slows down scrolling significantly.
It seems that a wheelSpeed value of around 3.5 actually cancels out the slowing effects of scroll-behavior: smooth. It's still jumpy compared to un-normalized scrolling, but is still much better. I probably wouldn't use it that way because who knows what side-effects it could have cross-browser/platform.
I don't have anything against using ScrollSmoother, I just don't want to be forced into using it for one particular effect.
This still feels far from an ideal solution. I think that my utility to implement css: sticky on particular inner sections is at best ok, but I was hoping to avoid massive DOM manipulation to begin with and it certainly doesn't do that. Cassie's suggestion of reparenting the pin is the easiest solution for sure, but shares the same issue of majorly manipulating the DOM and probably won't work in some edge cases. Scroll normalization results in choppy scroll on windows which isn't tenable, but is resolved by either A) using css smooth scrolling (kind of fixes it) or B| using ScrollSmoother. The former seems like a terrible idea that offers okay-ish results, and the latter completely solves the issue, but requires an entire plugin for a single effect.
In the end I think I'll have to go down the path of trying to make my own function to easily create position: sticky based pins so as to take advantage of browser implementations of pinning when nesting pinned sections. The fortunate side of the situation is that I'm working within an edge case so it's not a huge deal. The other side of the coin is that it will take a lot of footwork to accommodate a fairly uncommon case.
A rather mundane conclusion to the thread, but sometimes you've just got to write JS.
Share on other sites
GreenSock    17,226 Likes (Superhero)
1 hour ago, SteveS said:
It seems that a wheelSpeed value of around 3.5 actually cancels out the slowing effects of scroll-behavior: smooth. It's still jumpy compared to un-normalized scrolling, but is still much better. I probably wouldn't use it that way because who knows what side-effects it could have cross-browser/platform.
Oh yeah, I definitely wouldn't recommend doing that.
My vote: ScrollSmoother for the win!
Share on other sites
Create an account or sign in to comment
You need to be a member in order to leave a comment
Sign up for a new account in our community. It's easy!
Register a new account
Already have an account? Sign in here.
Sign in to follow this   Followers 3
Go to topic listing
Recently Browsing   0 members
No registered users viewing this page.
Alternative Bottom Layering Method
“This is by far the fastest and most active community I've ever seen for getting personalized answers to questions. Only with the help of GSAP and this forum was I able to accomplish my project.”
“The best thing about GSAP is that it just works, and it works well. On every single browser I’ve tested.”
“I absolutely love working with GSAP. It’s been one of the most enjoyable things I’ve ever studied and the team do a fantastic job of making it first of all but also in the fantastic forums. I’ve managed to learn so much from that so I’ll always be gratefu”
“This is why I have absolutely no issues with paying for a subscription to GSAP, great product and awesome forum!”
“It's shocking the @w3c didn't use @greensock as a model of how to do animation via code. Did they even ask animators what they use?”
“GreenSock is the best thing that happened to SVG animations since SVG animations.”
“I’ve long felt like GSAP is the best kept secret in JavaScript.”
“Reading through the GreenSock docs; been amazed like 14 times so far! How can a library be SO complete? Been using that for about 2 years now but man... This the first time I feel this way about a library.”
“GreenSock has encouraged me to play with the code, to dream up new and exciting things to do.”
Sign Up For Our Newsletter
Get the latest updates on GreenSock products, exclusive offers, and more right in your inbox.
Your information will always be kept confidential.
Thanks for signing up!
Now you'll begin receiving the latest GreenSock updates, exclusive offers, and more right in your inbox. Welcome aboard.