Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
romain.gr

Scroll Trigger ScrollTrigger.matchMedia bug, next scrollTrigger not recalculated after resize.

Recommended Posts

Hi, 

 

I'm currently working on a website using Gsap ScrollTrigger.

 

What I'm trying to achieve is showing a "previous-next post" button when the user has reached the bottom of the page. Which is working almost ok when the page is not resized.

 

So on the page I have 2 scrollTriggers:

 

1. A horizontal gallery of images (with a media match)

2. The previous-next button.

 

1:

        let slider = document.querySelector('.hor-slide--project');
        
        setTimeout(function(){
            ScrollTrigger.matchMedia({
                "(min-width: 992px)": function() {
                    gsap.to(slider, {
                        x: () => -(slider.scrollWidth - document.documentElement.clientWidth) + 'px',
                        ease: 'none',
                        scrollTrigger: {
                            trigger: '.hor-slider-container',
                            start: 'top top',
                            //pinReparent: true,
                            invalidateOnRefresh: true,
                            pin: true,
                            // scrub: .25,
                            scrub: 0,
                            // end: () => '+=' + slider.offsetWidth
                            // end: 4000,
                            end: () => slider.scrollWidth,
                        }
                    });
                },
            });
        }, 1);

2:

 

        setTimeout(function(){
            ScrollTrigger.create({
                trigger: '.single-project',
                start: 'bottom bottom+=50px',
                //end: 'bottom bottom',
                invalidateOnRefresh: true,
                //markers: true,
                onEnter: self => {
                    gsap.to('.prev-next', 1, {y: '-100%', ease: Expo.easeOut})
                },
                onLeaveBack: self => {
                    gsap.to('.prev-next', .5, {y: '0', ease: Expo.easeOut})
                }
            });
        }, 100);

I'm using setTimeout because in addition to gsap scrollTrigger I'm using Barba.js, and I need to delay, but it doesn't seem to be the problem, I removed the setTimeout and the problem still occurs.

 

For the second scrollTrigger, I have used onEnter and onLeaveBack, this might not be the best way but that's the only way I found so far (I might be part of the problem), so 50px before the bottom of the '.single-project' block reach the bottom of the viewport (start: 'bottom bottom+=50px'), show the prev-next, otherwise hide it.

 

The problem is that when I resize the window from mobile (< 992px) to desktop (> 992px), the prev-next button is now showing to early, before I reach the bottom of the page.

 

Step to reproduce the bug:

 

1. Load the page on desktop, scroll to the bottom, the prev-next is showing (great)

2. Resize the window (< 992px), the first horizontal gallery scroll is "killed", scroll to the bottom, the prev-next is still showing at the right time (amazing)

3. Re-resize the window (> 992px), the first horizontal gallery is "recreated", and now if you scroll around the page, you can see prev-next showing too early, before you reached the end of the page.

 

I tried refresh and also invalidateOnRefresh true or false, without success, it doesn't want to work. I guess I'm doing something wrong, probably the way I try to show the prev-next, using onEnter and onLeaveBack. Must be a more clever way to do that.

 

Thank you.

See the Pen MWomQmz by romaingranai (@romaingranai) on CodePen

Link to comment
Share on other sites

I'm traveling at the moment, so I don't have much time to dig into this but I figured I'd mention a few quick things:

  • You've got a collapsing margin issue with your pin, so I'd recommend using padding instead if you can. Basically, if your pinned element has a margin-top and it gets enclosed in the pin, that margin-top will push it down from the pin-container. It's not a bug - it's a logic issue with the way CSS works. 
  • You should always create your ScrollTriggers in the order they occur on the page so that they refresh() in the proper order. Alternatively, you can influence that with the refreshPriority. In your case, you want your back-next element to have the lowest priority (default is 0, so go negative). 
  • You were creating new tween instances in your onEnter/onLeaveBack, so those can't get reverted on refresh so I'd recommend doing a regular gsap.to() with a ScrollTrigger and then define toggleActions: "play none none reverse"

Is this closer to what you wanted? 

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

  • Like 2
Link to comment
Share on other sites

Hi Jack,

 

That's definitely what I want, thank you. I knew there was a more clever to do.

 

However, I'm getting confused about your second point:

  • You should always create your ScrollTriggers in the order they occur on the page so that they refresh() in the proper order. Alternatively, you can influence that with the refreshPriority. In your case, you want your back-next element to have the lowest priority (default is 0, so go negative). 

Isn't it already the case? I created the 2 ScrollTriggers in order they appears, does it need a refreshPriority if the 2 scrollTrigger are created in the right order? As I understand, if they are created in the right order, they gonna refresh in that same order, thus the refreshPriority is unneeded for the second one. Am I right? 

 

Thank you.

Link to comment
Share on other sites

3 hours ago, romain.gr said:

Isn't it already the case? I created the 2 ScrollTriggers in order they appears, does it need a refreshPriority if the 2 scrollTrigger are created in the right order? As I understand, if they are created in the right order, they gonna refresh in that same order, thus the refreshPriority is unneeded for the second one. Am I right? 

Yes, but you've got one inside of a .matchMedia() so it'll all work fine the first time but then when you resize the screen enough to no longer match that one, it'll get killed, and then if you resize enough to match again, a new one will be created which will now be AFTER that other one, so they're out of order now. See what I mean? 

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