Jump to content
GreenSock

delivous

ScrollTrigger: Weird behaviour at the endpoint

Recommended Posts

I'm working on a project that has multiple ScrollTriggers with long timelines. Everything works fine until the end of the pinned container. Once you reach the end of the container, the contents jumps to the bottom.

I've created a pen showing the method I'm using to create the ScrollTriggers and the timelines. However, I wasn't able to recreate the issue on codepen.

Below is the screen recording of the issue. Also, while I was trying to record this video I tried it on fullscreen first and apparently the issue disappeared.
 

Any idea what could be causing this?

Thanks in advance!

 

See the Pen gOvMNdP?editors=0010 by delivious (@delivious) on CodePen

Link to comment
Share on other sites

Welcome to the forums @delivous

 

It's really hard to advise without having some sort of demo that can reproduce the issue. I would suggest trying to isolate the problem, commenting out code until figure out what the culprit is.

  • Thanks 1
Link to comment
Share on other sites

Strange indeed. I noticed that your site has scroll-behavior: smooth on it. I'm wondering if that might be messing with something somehow.

 

 

 

  • Thanks 1
Link to comment
Share on other sites

Thank you for having a look at it. I did overwrite those declarations, however the issue is still there.

I also tried commenting out everything but that didn't help either.

Link to comment
Share on other sites

Are you absolutely positive you're using the latest version of all GSAP files (3.10.4 as of right now)? Maybe try:

console.log(ScrollTrigger.version)

 

  • Thanks 1
Link to comment
Share on other sites

Hey @GreenSock,

Yes, I just checked, the version is latest - 3.10.4.

Link to comment
Share on other sites

Hm. I'm not sure what to say - it's virtually impossible for us to troubleshoot if we can't reproduce it somehow. There must be something unique about your local environment there. 🤷‍♂️

  • Like 1
Link to comment
Share on other sites

Hey @GreenSock,

I understand. I tried coding the whole timeline again and found out that when I add this tween(at the end of the timeline) below is when the issue begins. i.e, the contents of the pinned container jumps offscreen to the bottom.

 

.fromTo('#prop_25', {
  scale: 1,
}, {
  scrollTrigger: {
    start: () => {pos += normH; return pos;},
    end: () => {pos += normH; return pos;},
    scrub: 0.5
  },
  scale: 3,
  ease: "expo.inOut"
});

As soon as I remove this tween, everything works fine. This isn't the only tween that's animating the scale value. I'm not sure how this could affect the pinned container.

I'm also setting display: flex  and overflow: hidden to the pinned container, if that helps.

Link to comment
Share on other sites

Is that a nested scrollTrigger by any chance?

 

You shouldn't have ScrollTriggered tweens inside a ScrollTriggered timeline. Big no-no!

 

  • Thanks 1
Link to comment
Share on other sites

Hey @Cassie,

Thank you for your response. I'm using the same technique used in this codepen(

See the Pen PoZKRLd?editors=0010 by Sicontis (@Sicontis) on CodePen

).

Actually, I've found the issue. The element('#prop_25') was a <figure> element, I changed it to a <div> and that fixed it.

Link to comment
Share on other sites

18 minutes ago, Cassie said:

You shouldn't have ScrollTriggered tweens inside a ScrollTriggered timeline. Big no-no!


Apologies I forgot to mention the changes. In the previous version, I had ScrollTriggered timeline and when I ran into this issue I decided to replace them with the ScrollTriggered tweens hoping that might solve the issue. But actually the culprit was the <figure> element.

Thank you all for your help! Really appreciated!

  • Like 1
Link to comment
Share on other sites

I've never seen timelines with a mixture of scrollTriggered tweens and non-scrollTriggered tweens added to them before.

 

Seems to be working but I'm not quite sure how? Tweens on a timeline are meant to be sequenced after one another whereas tweens with ScrollTriggers are triggered by a certain scroll position, so that's conflicting logic in my head... 

  • Thanks 1
Link to comment
Share on other sites

10 hours ago, Cassie said:

I've never seen timelines with a mixture of scrollTriggered tweens and non-scrollTriggered tweens added to them before.

 

Seems to be working but I'm not quite sure how? Tweens on a timeline are meant to be sequenced after one another whereas tweens with ScrollTriggers are triggered by a certain scroll position, so that's conflicting logic in my head...


Hey @Cassie,

Thank you for pointing that out. I was still facing issues, it was definitely how I was creating the timelines. After having a look at some examples, I redid everything again and it's working fine as expected now.

Again really appreciate your help,
Cheers!

Link to comment
Share on other sites

Hey @OSUblake @GreenSock@Cassie,

First of all I'm really sorry that I've made some quick assumptions before tracking down the real issue. After quite some back and forth; and restructuring the timelines, I noticed that the issue appears but only sometimes.

 

As you can see in the screen recording(https://vimeo.com/709507484), when I keep refreshing the page a few times, the pinned section's start point sometimes starts at the start of the previous container or sometimes where it is expected to. As previously mentioned, if the start point is shifted and I switch to fullscreen, the "start" point magically snaps back to where it is supposed to be. When I switch back to normal window, the start point doesn't snap back to top but stays where it is expected to be.

Assuming that the previous container's styling might be conflicting, I tried removing the previous section, but it does the same thing again but now with the very first section.i.e, the carousel. So maybe it's the way I'm creating the timeline?

At this point, I'm quite clueless as I've tried almost everything I can but haven't been able to figure out why this is happening. It'd be really great if someone could help me get to the bottom of this.

Again, as I'm not able to reproduce this issue on codepen, I'm attaching a minimal demo of how I'm structuring the timelines as well the updated live project(https://delivious.000webhostapp.com/safety-tech.php).

See the Pen LYQRwLP?editors=0010 by delivious (@delivious) on CodePen



Below is the full ScrollTrigger timeline logic:

(function() {
  'use strict';

  const ease_in = "circ.in";
  const ease_out = "circ.out";
  const ease_in_out = "circ.inOut";
  const expo_in = "expo.in";
  const expo_out = "expo.out";
  const expo_in_out = "expo.inOut";

  let boxer_tl,
      mobile,
      ww;

  let _a = {
    init: () => {
      _a.initVars();
      _a.initTimelines();
      _a.createTimeline();
      _a.attachEvents();
    },
    initVars: () => {
      ww = window.innerWidth;
      mobile = ww < 768;
    },
    initTimelines: () => {
      gsap.registerPlugin("ScrollTrigger");

      boxer_tl = gsap.timeline({
        defaults: {
          duration: 0.67,
          ease: ease_out
        },
        scrollTrigger: {
          trigger: ".boxerSection",
          start: "top top",
          end: "+=15000",
          markers: true,
          pin: true,
          scrub: 0.5
        }
      });
    },
    createTimeline: () => {

      boxer_tl.set("#boxer_svg, #subaru_boxer_engine, #subaru_boxer_engine_inner, .prop, #car_2_engine_1, #car_2_engine_2", {opacity: 0, autoAlpha: 0})
              .set("#boxer_title, .prop-conclude, .fullTitle, #prop_22, #prop_23, #prop_24, #prop_25, #prop_27, #prop_28, #prop_29, #prop_30, #prop_31, #prop_32", {yPercent: 100, opacity: 0, autoAlpha: 0})
              .set("#subaru_car", {scale: 0, opacity: 0, autoAlpha: 0, transformOrigin: "center center"})
              .set("#prop_1, #prop_2", {xPercent: mobile ? -20 : -50})
              .set("#prop_3", {scale: 0, xPercent: mobile ? -300 : 100, yPercent: mobile ? 0 : -50, transformOrigin: "center center"})
              .set("#car_2", {scale: 0, transformOrigin: "center center"})
              .set("#prop_10", {yPercent: mobile ? 500 : 100})
              .set("#prop_20", {yPercent: 0, opacity: 1, autoAlpha: 1});
      
      boxer_tl.add("boxer_intro", mobile ? 0.1 : 0.2)
              .to("#boxer_title", {yPercent: -50, opacity: 1, autoAlpha: 1}, "boxer_intro")
              .fromTo("#boxer_title", {yPercent: -50, opacity: 1, autoAlpha: 1, ease: expo_in}, {yPercent: -100, opacity: 0, autoAlpha: 0, ease: ease_in}, "boxer_intro+=0.5")
        
              .add("figure_in")
              .to("#boxer_svg", {opacity: 1, autoAlpha: 1}, "figure_in")
              .to("#subaru_car", {scale: 1, opacity: 1, autoAlpha: 1, transformOrigin: "center center"}, "-=0.5")
        
              .add("boxer_engine")
              .to("#subaru_boxer_engine", {opacity: 1, autoAlpha: 1}, "boxer_engine")
              
              // you've got a smooth operator
              .to("#prop_1", {opacity: 1, autoAlpha: 1, xPercent: 0}, "-=0.25")
              .to("#prop_2", {opacity: 1, autoAlpha: 1, xPercent: 0}, "-=0.25")
              .fromTo("#prop_2", {opacity: 1, autoAlpha: 1, xPercent: 0, ease: ease_in}, {opacity: 0, autoAlpha: 0, xPercent: mobile ? 150 : -150}, "+=0.5")
              .fromTo("#prop_1", {opacity: 1, autoAlpha: 1, xPercent: 0, ease: ease_in}, {opacity: 0, autoAlpha: 0, xPercent: mobile ? 150 : -150}, "-=0.25")
              .to("#prop_3", {scale: 1, opacity: 1, autoAlpha: 1, xPercent: 0, yPercent: mobile ? 0 : -50}, "-=0.75")
              
              // boxer engine
              .to("#subaru_boxer_engine_inner", {opacity: 1, autoAlpha: 1})
              .to("#prop_4", {opacity: 1, autoAlpha: 1}, "-=0.67")
              .to("#prop_5", {opacity: 1, autoAlpha: 1}, "-=0.25")
              .fromTo("#prop_5", {opacity: 1, autoAlpha: 1, ease: ease_in}, {opacity: 0, autoAlpha: 0}, "+=0.5")
              .fromTo("#prop_4", {opacity: 1, autoAlpha: 1, ease: ease_in}, {opacity: 0, autoAlpha: 0}, "-=0.25")
              .fromTo("#subaru_car", {scale: 1, opacity: 1, autoAlpha: 1, transformOrigin: "center center", ease: ease_in}, {scale: 0, opacity: 0, autoAlpha: 0, transformOrigin: "center center"}, "-=0.67")
              
              // inline engine
              .add("inline_engine", "-=0.67")
              .to("#car_2", {scale: 1, opacity: 1, autoAlpha: 1, transformOrigin: "center center"})
              .to("#car_2_engine_1", {opacity: 1, autoAlpha: 1})
              .to("#prop_6", {opacity: 1, autoAlpha: 1}, "-=0.67")
              .to("#prop_7", {opacity: 1, autoAlpha: 1}, "-=0.25")
              .fromTo("#prop_7", {opacity: 1, autoAlpha: 1, ease: ease_in}, {opacity: 0, autoAlpha: 0}, "+=0.5")
              .fromTo("#prop_6", {opacity: 1, autoAlpha: 1, ease: ease_in}, {opacity: 0, autoAlpha: 0}, "-=0.25")
              .fromTo("#car_2_engine_1", {opacity: 1, autoAlpha: 1, ease: ease_in}, {opacity: 0, autoAlpha: 0})
              
              // v type engine
              .add("v_type_engine")
              .to("#car_2_engine_2", {opacity: 1, autoAlpha: 1})
              .to("#prop_8", {opacity: 1, autoAlpha: 1}, "-=0.67")
              .to("#prop_9", {opacity: 1, autoAlpha: 1}, "-=0.25")
              .fromTo("#prop_9", {opacity: 1, autoAlpha: 1, ease: ease_in}, {opacity: 0, autoAlpha: 0, xPercent: mobile ? 0 : 100, yPercent: mobile ? -400 : 0}, mobile ? "+=0.5" : "+=0.5")
              .fromTo("#prop_8", {opacity: 1, autoAlpha: 1, ease: ease_in}, {opacity: 0, autoAlpha: 0, xPercent: mobile ? 0 : 100, yPercent: mobile ? -1500 : 0}, mobile ? "-=0.67" : "-=0.5")
              
              // clear the scene for next phase
              .add("clear_engine_scene")
              .fromTo("#prop_3", {opacity: 1, autoAlpha: 1, xPercent: 0, yPercent: mobile ? 0 : -50, ease: expo_in}, {opacity: 0, autoAlpha: 0, xPercent: mobile ? 0 : -100, yPercent: mobile ? -250 : -50}, mobile ? "-=0.84" : "-=0.84")
              .fromTo("#boxer_svg", {yPercent: 0, opacity: 1, autoAlpha: 1, ease: expo_in}, {yPercent: -100, opacity: 0, autoAlpha: 0}, "-=0.5")
        
              // conclude
              .add("conclude", "-=0.67")
              .to("#prop_10", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .to("#prop_11", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .to("#prop_12", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .to("#prop_13", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .to("#prop_14", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .to("#prop_15", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .to("#prop_16", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .to("#prop_17", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .to("#prop_18", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
        
              // clear conclude
              .add("clear_conclude")
              .to("#prop_20", {yPercent: -100, opacity: 0, autoAlpha: 0, ease: expo_in})
        
              // lineartronic cvt
              .add("lineartronic_cvt")
              .to("#prop_19", {yPercent: -50, opacity: 1, autoAlpha: 1}, "lineartronic_cvt")
              .to("#prop_19", {yPercent: -100, opacity: 0, autoAlpha: 0, ease: ease_in}, "lineartronic_cvt+=1")
              .to("#prop_21", {yPercent: -50, opacity: 1, autoAlpha: 1})
              .to("#prop_21", {yPercent: -100, opacity: 0, autoAlpha: 0, ease: ease_in}, "+=1")
              // lineartronic bg image
              .to("#prop_22", {yPercent: 0, opacity: 1, autoAlpha: 1}, "lineartronic_img")
              .to("#prop_23", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.5")
              .to("#prop_24", {opacity: 1, autoAlpha: 1, yPercent: 0}, "-=0.25")
              .fromTo("#prop_23", {opacity: 1, autoAlpha: 1, yPercent: 0, ease: ease_in}, {opacity: 0, autoAlpha: 0, yPercent: -100}, "+=0.5")
              .fromTo("#prop_24", {opacity: 1, autoAlpha: 1, yPercent: 0, ease: ease_in}, {opacity: 0, autoAlpha: 0, yPercent: -100}, "-=0.25")
              .fromTo("#prop_22", {yPercent: 0, opacity: 1, autoAlpha: 1, ease: ease_in}, { yPercent: -50, opacity: 0, autoAlpha: 0}, "-=0.67")
        
        
              // SI-Drive
              .add("si_drive")
              // steering_wheel
              .to("#prop_25", {yPercent: mobile ? -50 : 0, opacity: 1, autoAlpha: 1, ease: expo_out})
              .fromTo("#prop_25", {scale: 1, xPercent: "-=0", yPercent: mobile ? -50 : 0, ease: expo_in_out}, {scale: mobile ? 0.7 : 3, xPercent: mobile ? "-=0" : "-=60", yPercent: mobile ? -73 : -33})
        
              .to(mobile ? "#prop_28" : "#prop_27", {yPercent: 0, opacity: 1, autoAlpha: 1})
              .to(mobile ? "#prop_27" : "#prop_28", {yPercent: 0, opacity: 1, autoAlpha: 1}, "-=0.25")
              .fromTo(mobile ? "#prop_28" : "#prop_27", {yPercent: 0, opacity: 1, autoAlpha: 1, ease: ease_in}, {yPercent: -100, opacity: 0, autoAlpha: 0}, "+=0.5")
              .fromTo(mobile ? "#prop_27" : "#prop_28", {yPercent: 0, opacity: 1, autoAlpha: 1, ease: ease_in}, {yPercent: -100, opacity: 0, autoAlpha: 0}, "-=0.25")
        
              .to("#prop_33", {fill: '#DA9320'})
        
              .to(mobile ? "#prop_30" : "#prop_29", {yPercent: 0, opacity: 1, autoAlpha: 1}, "-=0.67")
              .to(mobile ? "#prop_29" : "#prop_30", {yPercent: 0, opacity: 1, autoAlpha: 1}, "-=0.25")
              .fromTo(mobile ? "#prop_30" : "#prop_29", {yPercent: 0, opacity: 1, autoAlpha: 1, ease: ease_in}, {yPercent: -100, opacity: 0, autoAlpha: 0}, "+=0.5")
              .fromTo(mobile ? "#prop_29" : "#prop_30", {yPercent: 0, opacity: 1, autoAlpha: 1, ease: ease_in}, {yPercent: -100, opacity: 0, autoAlpha: 0}, "-=0.25")
        
              .to(mobile ? "#prop_32" : "#prop_31", {yPercent: 0, opacity: 1, autoAlpha: 1})
              .to(mobile ? "#prop_31" : "#prop_32", {yPercent: 0, opacity: 1, autoAlpha: 1}, "-=0.25")
              .fromTo(mobile ? "#prop_32" : "#prop_31", {yPercent: 0, opacity: 1, autoAlpha: 1, ease: ease_in}, {yPercent: -100, opacity: 0, autoAlpha: 0}, "+=0.5")
              .fromTo(mobile ? "#prop_31" : "#prop_32", {yPercent: 0, opacity: 1, autoAlpha: 1, ease: ease_in}, {yPercent: -100, opacity: 0, autoAlpha: 0}, "-=0.1")
        
              .fromTo("#prop_25", {yPercent: mobile ? -73 : -33, ease: expo_in}, {yPercent: -183, opacity: 0, autoAlpha: 0}, "-=0.67");
              
    },
    attachEvents: () => {
      window.addEventListener('resize', _a.handleResize, false);
    },
    handleResize: () => {
      ScrollTrigger.refresh();
    }

  };

  window.addEventListener('load', _a.init, false);

})();

 

Link to comment
Share on other sites

Hey @Cassie,

Thank you again for your response! I'll try to implement that.

Link to comment
Share on other sites

And you don't need those resize and load event listeners as ScrollTrigger automatically does that.

  • Thanks 1
Link to comment
Share on other sites

6 hours ago, delivous said:

Again, as I'm not able to reproduce this issue on codepen, I'm attaching a minimal demo of how I'm structuring the timelines as well the updated live project(https://delivious.000webhostapp.com/safety-tech.php).

You said you were attaching a minimal demo. Did I miss it? I see a CodePen (which you said works fine)...and a link to a live site...where's the minimal demo that allows us to see the issue in context? It's virtually impossible to troubleshoot blind. Is there some way you can create a separate minimal demo with just some colored <div> elements that reliably reproduces the issue and send that to us? 

  • Like 1
Link to comment
Share on other sites

13 hours ago, GreenSock said:

Is there some way you can create a separate minimal demo with just some colored <div> elements that reliably reproduces the issue and send that to us? 


I tried reproducing the issue for a minimal demo, but again I couldn't as gsap had nothing to do with this issue. I'm really sorry for wasting your guys' time.

It turns out the issue was coming from the owl carousel that was sometimes being loaded before or after the GSAP code. I know, I feel really stupid for not noticing this sooner. I've combined the code to a single load event handler and now it's fixed!

Thank you all for your time and @GreenSock thank you for making GSAP public! It's truly amazing!

  • Like 2
Link to comment
Share on other sites

17 hours ago, OSUblake said:

And you don't need those resize and load event listeners as ScrollTrigger automatically does that.


Thank you, I've removed them.

  • Like 1
Link to comment
Share on other sites

7 hours ago, delivous said:

It turns out the issue was coming from the owl carousel that was sometimes being loaded before or after the GSAP code. I know, I feel really stupid for not noticing this sooner. I've combined the code to a single load event handler and now it's fixed!

Thank you all for your time and @GreenSock thank you for making GSAP public! It's truly amazing!

Glad you figured it out! No need to feel stupid - we've all done stuff like that before. It's the nature of development sometimes. 

 

Happy tweening!

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