Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
iDad5

ScrollTrigger Conceptual Question (Resizing)

Recommended Posts

I've built that page based on what I discussed here:

My question is not about the things I discussed in that thread (I've worked those out or around to my satisfaction)

 

I'm in the process of handling resizing of the page right now, and that's where I'm stuck.

 

What I want is that each panel always fills the available viewport  perfectly. Due to different browser quirks (especially with mobile browsers dynamically hiding browser-chrome elements)

  • I could not find a pure css version to achieve that. So I use Javascript to set the panel-elements to document.documentElement.clientWidth and height.
  • The container-element which is the ScrollTriggers trigger I set to n times the panel-height (having n-panels). 
  • On resize I do refresh those values.
  • Though ScrollTrigger usually is great with resizes what happens in my case  isn't exactly what I want. 
  • For one thing I would like to make sure that even after a significant resize the current visible panel will be still be the one visible.
  • As I potentially also have a lot of other recalculations to do  What I tried ist to disable the scrollTrigger on resize, resize my panels and container, scroll to the adequate position to keep the right panel in view and reenable ScrollTrigger (and refresh it).

 

Here is my problem: When the ScrollTrigger is created it wraps the container in a pin-spacer div of the exact height of the container (PinSpacing being set to false). With the Panels and container being sizes with CSS values of vh or vw or percentages the pin-spacer element adjusts to the new size. With me setting the values on each element with js the ScrollTrigger is not only not reacting as expected, but setting the pin-spacer back to its previous (pre resizing) value - and on top also resizing the container to said height.

 

My questions: Is this the intended behaviour for some valid reason I don't know about, or is this a mistake in may thinking? Or am I just missing something conceptually.

 

I'm willing to try to replicate this issue in CodePen, but I won't be truly simple, but if it seems worth investigation to some of you I will try.

Also my issue is independent from my possible resizing anomaly I've talked about in another thread, I can reproduce it on other machines too with the development site. 

 

Sidenote: It seems that in the TypeScript definitions the method refresh for a single ScrollTrigger Instance is missing and the following lines need //@ts-ignore as update() too seems not to be defined on a ScrollTrigger instance. And in the self.animation.currentLabel() somwhere also is a problem in the definition.

scrollTrigger:{
                start: 'top top',
                .....
                // @ts-ignore
                onToggle: self => {self.update(); this.findCurrentSlide(self.animation.currentLabel(), 'toggle');},
                // @ts-ignore
                onSnapComplete: self => {self.update(); this.findCurrentSlide(self.animation.currentLabel(), 'complete');},
            }

 

 

   

 

 

Link to comment
Share on other sites

Hi there @iDad5,

 

We ask for minimal demos because it's really difficult to problem solve from explanations alone.

Rather than looking at the code and being able to immediately get to the root of the issue you're asking people to try and understand your perspective on the issue, match that up with their knowledge of a tool and then blindly try and fill in the gaps. It's not the most effective way to ask for help! I know making a demo can be a bit of a faff, but it really helps us to help you.

 

58 minutes ago, iDad5 said:

With me setting the values on each element with js the ScrollTrigger is not only not reacting as expected, but setting the pin-spacer back to its previous (pre resizing) value - and on top also resizing the container to said height.

 

As long as you're setting the heights with JS before the scrollTrigger is created/refreshed there won't be any difference between that and standard CSS sizing - it's all affecting the same HTML properties at the end of the day.

 

If you can pop a demo together I'll take a look!

 

Thanks!

Link to comment
Share on other sites

Thank you @Cassie for taking the time to read my question. I apologize for having you inconvenienced with the lack of a demo.

 

As the whole thing is rather complex, as a first step I simplified the demo and did not disable and reenable the ScrollTrigger but simply did my resizing and a refresh to the ScrollTrigger. You can find the demo here:

See the Pen rNzrqmV by mdrei (@mdrei) on CodePen

 

 

After a resize Event I set the container element to the new height:

console.log('setting container to '+this.panels.length + ' times the viewport height:' + this.panels.length * Math.floor(this.winH) + 'px');
    gsap.set(this.container, {height: (this.panels.length * Math.floor(this.winH)).toString() + 'px'});

The console reports the new height.

after also adjusting the panels' height I do:

 

 ScrollTrigger.getById('st').refresh();

Regardless of that refresh the ScrollTrigger does its magic and works mostly as expected after the resizing.

 

But while the console reports the new height that is to be set to the container, the web-inspector (and the scrollbar) show, that ScrollTrigger has kept not only the pin -spacer element at it's original size, but also reset the container to its pre-resize height.

before-resize.thumb.jpg.4b466d714dd226954919630eb367a7ed.jpg 

 

after-resize.thumb.jpg.1048aa5af43b4cd38028996a1e84d012.jpg

 

The problem gets worse, when one resizes the window to n-times its previous height (having n panels) as the container gets smaller than the panels and no scrolling is possible.

 

As I described in my first post, I tried to remedy the situation by disabling the ScrollTrigger before doing my recalculations and enabling it afterwards, but that didn't help either.

 

I feel that this behavior is at least unexpected, but I know from previous discussions that there often is a very good reason for behavior the seems strange at first sight. Maybe there is a better way to do what I want, or a way to modify the behavior of ScrollTrigger that I haven't found in the documentation, that would help me.

 

Thanks a lot

 

 

 

 

Link to comment
Share on other sites

Oh, and the clearer way to formulate my conceptual question would have been:

 

"How is the size of the pin-spacer element that ScrollTriger puts around the affected elements calculates, and how do I refresh that size?"

Link to comment
Share on other sites

2 hours ago, iDad5 said:

Sidenote: It seems that in the TypeScript definitions the method refresh for a single ScrollTrigger Instance is missing and the following lines need //@ts-ignore as update() too seems not to be defined on a ScrollTrigger instance. And in the self.animation.currentLabel() somwhere also is a problem in the definition.

 

I've added refresh and update to the next release. Have you noticed anything else missing?

 

currentLabel isn't on the animation because an animation can be a Tween or a Timeline, and a Tween doesn't have a currentLabel method. If you need Timeline specific methods, you should do this.

(self.animation as GSAPTimeline).currentLabel();

 

  • Like 1
Link to comment
Share on other sites

@OSUblake thanks, and true, should have noticed that 

22 minutes ago, OSUblake said:
(self.animation as GSAPTimeline).currentLabel();

myself.

Link to comment
Share on other sites

I don't have a lot of time to dig into all that code, but from a cursory glance it looks like you're doing some highly unusual things that won't work well with all the complexities that ScrollTrigger already has to deal with. Pinning is quite tricky especially when it must accommodate all kinds of other triggers and pins, etc. Let me explain...

 

When you create a ScrollTrigger with pinning, it must record the inline styles so that it can revert them when refreshing to ensure that normal CSS rules get applied properly. ScrollTrigger has to basically strip everything back down and start from the top down to calculate everything properly, and extract any changes that it made to the layout, etc. You're trying to mess directly with the dimensions of pinning-related stuff (I wouldn't recommend that), so when it reverts things to "get out of the way", it's also losing your new height that you set in the inline styles as well. 

 

If you really need to mess with dimensions of pinning-related elements like that, it's probably best for you to do a tear-down and rebuild fresh (recreate the ScrollTrigger(s)) to ensure that the NEW styles you're setting are incorporated. 

 

Again, I don't have a lot of time right now to wrap my head around everything you're trying to do in there; this is highly unusual (I've literally never seen someone mess with things like that) and often when I see something like this, it's a clue that there's probably a much cleaner way to approach it from an engineering standpoint in your app but I'm not sure right now and it's kinda out of the scope we can typically help with in these forums. In the meantime, I can say that if your goal is to directly change pinning-related element dimensions, you should just tear things down and build them up again at that point. Let me know if that helps at all. 

 

Good luck!

  • Like 1
Link to comment
Share on other sites

Thanks a lot Jack @GreenSock!
I guessed as much after an other afternoon of experiments. I do know that my approach is unusual, and the reason I feel I have to do it that way are actually three:

 

First as I mentioned somewhere: mobile browsers and their (excuse my French) ****** way of changing and reporting viewport sizes.

Secondly: The site has to (against my strong recommendations) work with screen-filling background images on which only one hamburger-navigation icon, the image/project-title and the legally necessary (small)  navigation-menu has to be placed - discreetly - in white or black. As I have no idea which dimensions I deal with, I developed a system to calculate size and placement of those elements on the background image. I render those portion of the background image into an off-screen canvas an determine whether to use black or white on each element in question. (I'm loading a better hi-res background-image if necessary due to lager windows too). 

Third reason: the customer whishes that after resizing the window the before shown panel still is the one that's displayed afterwards. 

 

With all that is going on in part two I wanted to ask if I'm missing something obvious, before adding -the tear-down and rebuild of the ScrollTrigger to the mix. Thanks' a lot for the explanation and I will try to work it out your suggested way. 

 

PS.: If one of the goddesses and gods of this Forum has a conceptual solution that makes all that unnecessary and and works even better, I will be very thankful. 

Link to comment
Share on other sites

As I'm going to rework my project I have a question I can't find the answer to in the docs:

 

Is it doable to create a standalone ScrollTrigger, add a timeline as an animation to it, then remove said animation (via scroltTrigger.animation = null ? )

and add the animation again with scrollTrigger.animation = timeline? 

 

(Would give me more reusable and better readable code that way than killing and recreating from scratch I guess.)

 

 

Link to comment
Share on other sites

10 minutes ago, iDad5 said:

First as I mentioned somewhere: mobile browsers and their (excuse my French) ****** way of changing and reporting viewport sizes.

Secondly:

 

You can get around the viewport resizing with some fixed positioning and using a different scroller. It also makes it feel more like a native app. The only downside is that address bar will always be visible.

 

 

The only downside is that 

 

  • Like 1
Link to comment
Share on other sites

6 minutes ago, iDad5 said:

Is it doable to create a standalone ScrollTrigger, add a timeline as an animation to it, then remove said animation (via scroltTrigger.animation = null ? )

and add the animation again with scrollTrigger.animation = timeline? 

Nope, sorry. 

  • Like 1
Link to comment
Share on other sites

Thanks  @OSUblake I have seen that solution already, and am tempted to try it, but as screen real estate is most expensive  on mobile and the client very very much favors a super clean look I was aiming for another solution - if at all possible...

Link to comment
Share on other sites

3 minutes ago, GreenSock said:

Nope, sorry. 

Thank you for saving me the time trying. :-)

  • Like 1
Link to comment
Share on other sites

Ok - I somehow got it working...

Killing the ScrollTrigger and re-creating it worked as expected. I also gut the mobile address-bar issue covered - somehow - it is unavoidable that things won't go super smooth but it would be ok.

 

The thing is that snapping on mobile is super slow. I have used 'will-change' in my css and I made the same experience with an other page that works more standard ScrollTrigger wise. 

 

Before I sink more time and energy in that thing, I would be very interested to know if anyone has examples of a ScrollTrigger-page that snaps 'snappy' on mobile, or if it is just the ****** way mobile browsers handle scrolling and there is not much to be done right now. Thanks.

 

Link to comment
Share on other sites

15 hours ago, iDad5 said:

Third reason: the customer wishes that after resizing the window the before shown panel still is the one that's displayed afterwards. 

This is 100% the point where I would say - sorry - this isn't how browsers work and then show then every other page on the internet which also experiences layout shifts on resize. 😂 (I salute you for your patience, I have none for these kind of requests)

 

I would probably handle things a little more like this. Use a functional value for the end position and use invalidateOnRefresh to refresh that value on resize. Then the container could be positioned with whatever magic CSS gets around the mobile bar issue - (like Blakes solution).

Maybe it helps? Maybe I'm not understanding the issue you're facing though.

See the Pen MWvMMOm?editors=0011 by GreenSock (@GreenSock) on CodePen


 

16 hours ago, iDad5 said:

Thanks  @OSUblake I have seen that solution already, and am tempted to try it, but as screen real estate is most expensive  on mobile and the client very very much favors a super clean look I was aiming for another solution - if at all possible...


p.s. Blakes solution won't impact style at all - it's just wrapping everything in a different scroller. You can read more here https://www.bram.us/2016/05/02/prevent-overscroll-bounce-in-ios-mobilesafari-pure-css/

 

  • Like 2
Link to comment
Share on other sites

1 hour ago, Cassie said:

This is 100% the point where I would say - sorry - this isn't how browsers work and then show then every other page on the internet which also experiences layout shifts on resize. 😂 (I salute you for your patience, I have none for these kind of requests)

Well, to be honest, that is the easiest part to solve and I personally dislike it to, when I go to full-screen to get better look at an image (Architecture in this case)  and suddenly im at a totally different portion of the page.

Quote

I would probably handle things a little more like this. Use a functional value for the end position and use invalidateOnRefresh to refresh that value on resize. Then the container could be positioned with whatever magic CSS gets around the mobile bar issue - (like Blakes solution).

Maybe it helps? Maybe I'm not understanding the issue you're facing though.

Thank you for that suggestion, it seems like a good alternative approach to my labels and it handles resizes better. It is missing the on snapComplete etc. handlers, but those should be easily added in you solution too.
I was of a mind to use the labels of the panels semantically too when I started out with the project, but don't use them that far. I see a potential pitfall in using window.innerHeight within the ScrollTrigger, as that is one of the tricky parts in which situation to use window.innerHeight and when to use document.documentElement.cleintHeight, but it might work well. 

By now though I'm actually quite happy with killing the ScrollTrigger sorting my stuff and re-creating it. It seems a stable solution and as I would have to disable it anyhow while sorting my stuff and re-enable it afterwards, I'll stick with my approach for now. But thank you again for the clever solution. 

 

OSUblake's suggestion keeps (if working) the address-bar always visible on mobile which would steal those pixels from the page, and I would love to use them when possible. Actually I have a solution that only slightly stutters when the Address-bar is hidden, and I would be quite happy with that, as for the rest of the experience the impression is a lot cleaner. The Problem with the experience is, that ScrollTrigger snapping is everything but smooth on iPad and iPhone.  I guess the best solution would be to recreate the behavior with a draggable solution on mobile but I feel that this ist just too much work right now. 

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