Jump to content
GreenSock

SteveS

Alternative Bottom Layering Method

Recommended Posts

I was trying to achieve the bottom layering effect from this example:

See the Pen BaowPwo by GreenSock (@GreenSock) on CodePen

 

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

Link to comment
Share on other sites

Looks fine to me!

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

It feels like there's always an edge case of some sort with these 'panel' type scroll animations. 🥲

Link to comment
Share on other sites

@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 🙃

  • Like 1
Link to comment
Share on other sites

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.

  • Like 1
Link to comment
Share on other sites

@GreenSock Do you have any input on this? Perhaps there's a known method for nesting pins that I am not aware of?

 

Link to comment
Share on other sites

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? 
Link to comment
Share on other sites

@GreenSock No real rush.

Goal: Nested pinning of sections that works on desktop.

TLDR:

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

Screenshot:
image.thumb.png.1b5b6a76e69a65224785b57069a68ac0.png

image.thumb.png.d0cc81f7467d254f70461118b63cdb49.png

 

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.

 

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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. 

Link to comment
Share on other sites

@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:

https://www.loom.com/share/8e43e5a7bca24423aad541ab14da366f

 

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.

Link to comment
Share on other sites

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. 

Link to comment
Share on other sites

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. 

Link to comment
Share on other sites


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.

Link to comment
Share on other sites

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! ;) 

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