Jump to content
Search Community

ScrollTrigger and HighwayJS

Duet Colin test
Moderator Tag

Recommended Posts

I'm having 1 issue with the combination of HighwayJS + Scrolltrigger. 

I wanted to demonstrate this issue in Codepen, but I can't figure out how to simulate the problem in Codepen, because I need to have a page transition in place and therefore I need 2 pages. Tried to do this with 2 codepen's. But it doesn't seem to work. So I will post the links to this specific project and a screencap to demonstrate the problem.

The problem is as follows;

On a homepage I have a carousel. Carousel functions with ScrollTrigger. It's pinned once it hits the top of the viewport. This all works fine when you land directly on the homepage. But as soon as you land on the homepage coming from another page within this website it doesn't function properly. The whole carousel disappears when it's Pinned (Fixed). 

The internal page transitions are without a refresh with the help of HighwayJS 

The whole problem doesn't occur when I change the pinType to 'transform'.  But this pinType has a weird effect to the UX. It's bouncing a bit scrolling through the slides.. Looks fragile. 


To replicate the issue

Start here > https://favelastreet.flywheelsites.com/about-us/
Open nav en click on "Favela Street" to go to the homepage, scroll down, once you see the carousel, it disappears when it hits top of the viewport.

 

Screencap

 

 

Remark
I kill all Scrolltriggers. I also use this script in order to refresh all Scrolltriggers as well.

        H.on('NAVIGATE_OUT', ({ from, trigger, location }) => {
            ScrollTrigger.getAll().forEach(st => st.refresh())
            ScrollTrigger.clearScrollMemory( ) ;
        });


ScrollTrigger part of the Carousel (carousel itself is SwiperJS)

        this.carouselST = ScrollTrigger.create({
            trigger: ".js_container",
            pin:true,
            start: "top top",
            // pinType: 'transform', >> If this line is uncommented the carousel works fine
            end:'+='+ (window.innerHeight * 2) + 'px',
            onUpdate: (self) => {

                const currentSlide = this.swiperImageCarousel.realIndex + 1

                if(self.direction === 1)
                {
                    if ((self.progress * 100) > (percentage * currentSlide))
                    {
                        this.swiperImageCarousel.slideNext(500, false)
                        $('.js_carouselIndicator').removeClass('-active')
                        $('.js_carouselIndicator' + this.swiperImageCarousel.realIndex).addClass('-active')
                    }
                } else if(self.direction === -1) {
                    if((self.progress * 100) < (percentage * currentSlide)) {
                        this.swiperImageCarousel.slidePrev(500, false)
                        $('.js_carouselIndicator').removeClass('-active')
                        $('.js_carouselIndicator' + this.swiperImageCarousel.realIndex).addClass('-active')
                    }
                }

            }
        });

 

Page Transition

// File: custom-transition.js
// Import Highway
import Highway from '@dogstudio/highway'

import gsap from 'gsap'
import Experience from "../Experience";

class DefaultTransition extends Highway.Transition {

    // Built-in methods
    in({ from, to, trigger, done }) {

        // Get color theme of next page
        const themeColors = to.dataset.theme
        const colors = themeColors.split("_")

        const tlPageTransition = gsap.timeline()

        // Set new page to current Scroll position
        tlPageTransition.set(to, {y:window.scrollY})

        // Slide in New Page
        this.experience = new Experience()
        this.responsive = this.experience.responsive
        let slideParam = -50;

        // Slide to the left
        tlPageTransition.to('#js_wrapper', {duration:2,xPercent:slideParam,ease:"power3.inOut",
        onComplete: () => {

            // Set the Wrapper to 0 on the X axis and remove the old page
            tlPageTransition.set('#js_wrapper', {xPercent:0,onComplete: () => {
                from.remove()
            }})

            // Position new page back to top and instant scroll back to top
            tlPageTransition.set(to,{y:0,
                onComplete:() => {
                    window.scrollTo({
                        top: 0,
                        behavior: "instant"
                    })
                    done()

                }
            })

        }})

        // Set new colors
        tlPageTransition.to('#side',{duration:1, color: colors[0]},'-=1')
        tlPageTransition.to('.js_openNav',{duration:1, backgroundColor: colors[0]},'-=1')
        tlPageTransition.to('body',{duration:1, backgroundColor: colors[1]},'-=1')


    }
    out({ from, trigger, done }) {
        done()
    }
}

// Don`t forget to export your transition
export default DefaultTransition;

 

Link to comment
Share on other sites

Hi @Duet Colin,

 

Is quite difficult for us to debug a live site, especially one that has a few complexities in it (great job by the way!!! 🎉). On top of that we can't offer a lot of support for third party plugins like the one you are using.

 

What you could try is create a minimal demo in either Stackblitz or Codesandbox. They allow you to install different packages and create routes in them so it's more complete than Codepen, in that aspect at least.

 

In Stackblitz create a Blank Javascript project: https://stackblitz.com/

In Codesandbox create a Vanilla Codesandbox: https://codesandbox.io/s/

 

The only advice I can offer right now is try to update GSAP to the latest version (3.11.3) and also this:

H.on('NAVIGATE_OUT', ({ from, trigger, location }) => {
  ScrollTrigger.getAll().forEach(st => st.refresh())
  ScrollTrigger.clearScrollMemory( ) ;
});

With that code, you actually are not killing any ScrollTrigger instance, just refreshing all the instances one by one and then clearing the scroll memory. If you want to refresh all the ScrollTrigger instances just run the refresh method in the main ScrollTrigger object and not on each instance:

H.on('NAVIGATE_OUT', ({ from, trigger, location }) => {
  ScrollTrigger.refresh();
  ScrollTrigger.clearScrollMemory( ) ;
});

https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.refresh()

 

If you actually want to kill all the instances, just execute the killAll method on the main object:

H.on('NAVIGATE_OUT', ({ from, trigger, location }) => {
  ScrollTrigger.refresh();
  ScrollTrigger.clearScrollMemory();
  ScrollTrigger.killAll();
});

Although I do't know exactly what's the point of refreshing all the instances if you want to kill all of them, or perhaps I'm misunderstanding and that's not what you're trying to do.

 

Finally you mentioned that removing the pinType option from the configuration object makes the slider work as expected. Removing that causes some other issue that doesn't make it an option? Also I noticed that you are using a plugin (Swiper I believe), perhaps that is causing the issue. I noticed that a very small value is set to the top position of the element and when is removed it kind of works:

oYyr89b.png

Without the top value:

lMLoNFv.png

 

Try removing Swiper and see if it works as expected as well. You can switch swiper for the Observer Plugin. Here you can see an example showing how to combine it with ScrollTrigger:

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

 

Hopefully this helps in some way. Let us know how it works.

 

Happy Tweening!

Link to comment
Share on other sites

@Rodrigo thanks for your compliment and your response! I didn't know the existence of codesandbox. Love it!

 

I created a little demo hero > https://codesandbox.io/s/cool-shadow-kkeorm

 

Now you see a difference between 

1) hard refreshing the carousel page and looking at the Pinned section and

2) Going from "home" to the "carousel page".

 

The pinned part of the Scrolltrigger section reacts slightly different. 

 

by the way:

In my local setup I already removed all the swiper/carousel logic and just went with 1 <h1>, the problem was still occured..

Link to comment
Share on other sites

Hi,

 

The problem is that there is a layout shift after the transition, so the height recorded by ScrollTrigger is wrong after that element leaves, which causes the problems.

https://i.imgur.com/pwSGydI.mp4

If possible use an event listener in your transition, to create the ScrollTrigger instance(s) after the transition is complete in order to have the correct height of the container where you have the slider.

 

I'm not sure I grasp how the API of this library works but I would try something here:

tlPageTransition.to(from, {
  duration: 2,
  xPercent: -50,
  ease: "power3.inOut",
  onComplete: () => {
    from.remove();
    // HERE CREATE SCROLLTRIGGER INSTANCES
    // Position new page back to top and instant scroll back to top
    tlPageTransition.set(to, {
      y: 0,
      onComplete: () => {
        window.scrollTo({
          top: 0,
          behavior: "instant"
        });
        done();
      }
    });
  }
});

Finally is a bit peculiar to say the least, adding an instance to a timeline after a single tween of the same timeline has completed. Just do this:

tlPageTransition.to(from, {
  duration: 2,
  xPercent: -50,
  ease: "power3.inOut",
  onComplete: () => {
    from.remove();
  }
})
// Position new page back to top and instant scroll back to top
.set(to, {
  y: 0,
  onComplete: () => {
    window.scrollTo({
      top: 0,
      behavior: "instant"
    });
  }
})
.call(done);
// HERE CREATE SCROLLTRIGGER INSTANCES

https://greensock.com/docs/v3/GSAP/Timeline/call()

 

Hope this helps you. If you have any other questions, let us know.

 

Happy Tweening!

Link to comment
Share on other sites

Hi @Rodrigo,

 

Thanks again for your reply. I've added your remarks and also changed the code a bit so it behaves a bit more like the exact website.

 

https://codesandbox.io/s/cool-shadow-kkeorm

 

The part you're referring to is the index.js:38
This callback will only execute once the done method is called in the in() method of the transition.

 

I hope you have an idea how to solve this. Thanks!

 

Link to comment
Share on other sites

Hi,

 

I think this issue is related to the way HighwayJS works. I forked your sandbox and created the most basic slider controlled by ScrollTrigger and the result is the same:

https://codesandbox.io/s/serverless-worker-7ievqg?file=/carousel.html

 

Using the same HTML and CSS but without Highway it works as expected:

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

 

As you can see GSAP and ScrollTrigger are doing exactly what they are supposed to do. Unfortunately we don't have the resources to support and debug issues that come from third party tools and libraries, as we must focus our attention on GSAP related issues. I know for personal experience that is not fun when something doesn't work the way is expected and not having a solution for it.

 

The final advice I can give you is t explore a way to solve the CSS issue (the top position I mentioned in a previous post), perhaps using the onEnter callback to set those styles.

 

Sorry I can't be of any help in solving this and hopefully another user can offer some advice on this.

 

Happy Tweening!

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