Jump to content
GreenSock

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

Horizontall scrolltrigger with animated child elements

Recommended Posts

Hello, so I created a new topic regarding my problem. Basically I have a  structure similar to demo in codepen:

 

 

 

 

 What I need is to animate elements inside every section when they appear in the viewport. Now they animate all in the same time. Next question: it is possible in onEnter callback also have an element which trigger onEnter callback? 

 

Thank you for your help.

See the Pen RwrYmvR by luk-z-horec (@luk-z-horec) on CodePen

Link to comment
Share on other sites

Hey Lukas. I answered pretty much this same question yesterday here:

 

Short answer: you need to use the horizontal offset of the sections since they are all positioned at the top of the page:

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

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

Hi @ZachSaucier, may I have another question, I updated the pin above. And I have a little problem. Now I have there two scrollTriggers per each element (forEach cycle), first when elements came to screen from right and second when it goes away from left, and it's not working correctly. When I have just single scrolltrigger per element it is working as expected.

 

 

EDIT: I found solution here in one topic, when i use immediateRender: false it's start working, but I cant see it in a documentation, dont know why this prop helps.

Link to comment
Share on other sites

Hey Lukas. This is because your .from() tween sets the position initially. The ScrollTrigger tween then uses that cached value as the start point. Does that make sense?

 

Besides that, since both of your ScrollTriggers have a numerical scrub you're going to have conflict between their animations in some cases. It's probably not a good idea to use two separate ScrollTriggers affecting the same properties of the same elements so soon after each other, especially with a numerical scrub value.

 

I recommend either of the following options:

  • Use a single ScrollTrigger (applied to a timeline) for both the intro and exit.
  • Create a container element so that you can apply the ScrollTriggers and animations to separate elements that visually affect the same thing. 
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Again thank you 🤗 Yeah that immediateRender make me sense.

 

The other thing what you are pointing about, I know what you think what can happend. I know how to fix it with that additional container, but not with that single ScrollTrigger. How can I create single ScrollTrigger when there are two different "start" and "end" points?  🤔

Link to comment
Share on other sites

1 hour ago, LukasZahorec said:

How can I create single ScrollTrigger when there are two different "start" and "end" points?

If you use a timeline you would create a timeline with two tweens with some space between (probably using the position parameter of the second tween). The ScrollTrigger's start value would be the start value of your current entry ScrollTrigger. The end would be the end value of your current exit ScrollTrigger. Does that make sense?

 

Alternatively you could use the onEnter and onLeave callbacks to fire entry and exit animations. Just make sure they have overwrite: 'auto' to kill off each other if you do that.

  • Thanks 1
Link to comment
Share on other sites

Hey guys,

I just wanted to share my version of a similar codepen that I had built when ScrollTrigger was in beta but after coming across this thread I actually made some tweaks. So here is my updated codepen: 

See the Pen 303006b755b44294fd10efcaaeb8068e by robbiecren07 (@robbiecren07) on CodePen

 

Right now it works as planned in Codepen @ZachSaucier maybe you could do a quick quality check on my gsap code?? 😅

 

I did come across an issue when I took my code and placed it in another project on my localhost, the padding & height in the "pin-spacer" are not populating correctly. The project I placed it in has a bunch of timelines, scrolltriggers and another scrolltrigger pin section. So its going to take me some time to create a Codepen to recreate the issue.

 

  • Like 1
Link to comment
Share on other sites

Good work, @RobbieC! Nothing immediately jumps out to me as bad practice :) 

  • Like 1
Link to comment
Share on other sites

@ZachSaucier So I changed:

.forEach(function(elem) {

to:

.forEach(elem => {

And I actually got a more accurate animation on the ".secondAn" images, they seem to all visually start in the same location (Which is what i want). But when I had it with function, the starting point seemed to change for each image.

 

Can you help me understand the main difference in using function vs arrow, I have tried to do some research but its still a little unclear to me. 

Link to comment
Share on other sites

I see nothing in your code that would make it behave differently with an arrow function. Are you absolutely positive you're getting different behavior and that's the only thing you changed? 

 

Arrow functions differ from regular functions in that:

  • Scope is locked, meaning "this" inside the function is based on what it was in the context that arrow function was created. It can't be changed. 
  • You can't reference an "arguments" object in the function. 
  • They don't re implicitly return in the short syntax, so () => "blah"; is the same thing as () => { return "blah"; }

 

  • Like 1
Link to comment
Share on other sites

You are correct, there is no difference. Its a window resize issue. Can you help me???

 

To create the issue please open the codepen in "editor view", play the animation till you get to the bottom of page (like below image). 

Capture.PNG

 

 

Now slide the codepen divider bar that splits the code from the visual content, up (Like below image). You will notice that the last image is gone. 

Capture2.thumb.PNG.5cf879bc8e0de2ea6f0a5084b4e03cc1.PNG

 

So it leads me to believe that I need to add a refresh event (which I need help with). 

Link to comment
Share on other sites

You shouldn't have horizontal: true on anything. That's only for if you're setting everything up for your PAGE scrolling horizontally instead of vertically. 

  • Like 1
Link to comment
Share on other sites

Dang I thought I had something here. Well at least it works for someone that is doing a horizontal page layout.

 

But it is possible to achieve the same animation but for a vertical scrolling page with a horizontal pin section? I just have to change my logic/calculations for the trigger, start & end on the "tl2" timeline?

Link to comment
Share on other sites

Some tips:

  1. Don't nest scrollTriggers inside children of timelines. You were doing that. Either a timeline can control the tween's playhead or the ScrollTrigger can, not both. :)
  2. It doesn't do anything to have a "delay" on a tween/timeline that has a scrollTrigger that's set to scrub. I'm not sure what you were expecting that to do, but the animation will be paused initially by the ScrollTrigger and then its playhead will progress as the scrollbar moves between the start and end. There's no delay. 
  3. There wasn't really a reason to do gsap.utils.toArray(".firstAn").forEach(...). You can just use a single tween to do what you were doing there. 

I assume this is sorta what you were looking for? 

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

  • Like 3
Link to comment
Share on other sites

42 minutes ago, GreenSock said:

I assume this is sorta what you were looking for? 

That is exactly what I was going for. I let my thinking over complicate things. The last few months have been really hard for me trying to relearn things. I really need to take Carl's course.

Link to comment
Share on other sites

No no, don't feel bad, @RobbieC - this isn't a simple concept for most people to grasp. I had to think it through for a bit too. I hope it didn't come off as if I was saying this was trivial and you should have known. 

 

Trust me - we've all had plenty of times when we over-complicated things and then we see a simpler solution and think "OH! Why didn't I think of that?". 

 

Don't beat yourself up. I'm glad you chimed in here and shared. 

 

Happy scrolling! 👍

  • Like 1
Link to comment
Share on other sites

Nope it didn't. That's the kind of feedback I like. Your tips cleared a lot of things up for me.

 

Thank you!

Link to comment
Share on other sites

  • 2 weeks later...

@GreenSock I have been messing with the the codepen you created for me above and I ran into a issue when i brought it over to my localhost. Once again i'm having trouble recreating the issue on Codepen so you could see it. I'm like 99% sure it has something to do with the images not being fully loaded before the scrolltrigger calculates. Here is the Codepen I was trying to recreate the issue on:

See the Pen c904f1e5295f3fb1864090bf680603ef by robbiecren07 (@robbiecren07) on CodePen

 

I created a animated red line above and below the portfolio section that have markers enabled. On my locahost once I scroll into the portfolio section and the 3rd image starts to come into view, the trigger marker for the bottom red line comes into view and triggers, then once the portfolio section ends all the rest of my scrolltriggerd animations are jacked up. 

If you notice on the codepen the pin-spacer the height and padding are 5000px+, well on my localhost the pin-spacer height is 2000px and padding 1300px.

 

I have tried wrapping the GSAP code in:

function init(){
 // GSAP CODE
}

window.addEventListener('load', function(){
    init();
});

I have even tried what Jonathan recommended here:

 

My pin spacer height / padding was still in the 2000px+ range. I also tested it on 3 different browsers and made sure the cache was cleared.

 

I know its hard to debug anything with out a codepen showing the issue. So I will continue working on getting my issue displayed on the codepen.

 

Until then, could you point me to another post or tutorial for integrating a imagesloaded or lazy load with GSAP? I have tried to use the lazyload codepen on the scrolltrigger doc page, I couldn't get it working.

Link to comment
Share on other sites

A sure way to test whether or not it is an issue of the images loading: set explicit widths and heights on them. Often times it's good to do this anyway. 

 

Another way to check if they're loaded:

window.addEventListener('load', () => {
  const images = document.querySelectorAll('img');
  let count = 0;
  images.forEach(img => img.loaded ? count++ : null);
  
  console.log(images.length, count);
});

Or you could use a small library that does proper checking like imagesloaded.

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

Thank you @ZachSaucier for the quick reply and the feedback. 

3 hours ago, ZachSaucier said:

set explicit widths and heights

I will do this moving forward, makes sense and good advise - thank you!

 

So I set width & height and also added the check if images are loaded, like you suggested and it didn't resolve my issue. The images are being loaded at the same time of the first painting. I also added "defer" to both my JS script calls and after checking the "Network" waterfall in Chrome, my images are being loaded fully before the JS file even loads. So I think I ruled out the issue being the images not being fully loaded before the scrolltrigger calculates.

 

As I was typing this reply, I was messing with my JS files trying to debug it and create the issue on codepen, come to find out.... Its the order of my GSAP code in my JS file.... I was calling the ".hr" gsap code before the "portfolio" code... I guess what had me confused is that since i'm using:

const line = document.querySelectorAll(".hr");

        line.forEach((elem) => {
          gsap.from(elem, {
            duration: 1,
            width: "0",
            ease: "power3.inOut",
            scrollTrigger: {
              markers: true,
              trigger: elem,
              start: "top 80%",
              end: "bottom 10%",
              toggleActions: "play reverse play reverse"
            }
          })
       });

and this ".hr" animation is being use in multiple locations on the page, I still need to make sure the order is correct and place it where the last ".hr" is actually being called in the JS file. So for this instant if I use the ".hr" before and after the "portfolio" gsap code, I need to be placing it after the "portfolio" code in the JS file. 

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...

I have a question/issue once again on this CodePen: 

See the Pen QWyKJMg by robbiecren07 (@robbiecren07) on CodePen

The best way to see the issue im having is to view the pen in Full Page View, I created a spacer that is 900vh (to act like there is a lot of content above the portfolio section), when you scroll down and reach the portfolio section and once the scrolltrigger starts it moves SUPER fast like not even two clicks on the mousewheel and the scrolltrigger end. This shouldn't be happening and I'm not sure why. If you change the spacer-lg from 900vh to 100vh and run the code, you will see that once you get to the portfolio section it moves a lot slower and more natural.

 

The more content/sections I add above the portfolio section, the faster the scrolltrigger moves in the portfolio section, I don't understand why or whats going on. Also on my project I have lots of scrolltriggers but this is the only one that is effected like this, which leads me to believe it has something to do with the the trigger and end trigger.

 

Any input would be much appreciated, Thanks.

Link to comment
Share on other sites

  • 2 weeks later...

@ZachSaucier Sorry for the delayed reply, did you mean .offsetY? cause it returns NaN. I'm not using jQuery in my project, so I tried .offsetTop but that returns the value from the top of the page to the top the container which is like 15,000px which in return makes the endTrigger value like 17,000px which is way to much. 

Link to comment
Share on other sites

I meant offsetTop but I was mistaken anyway, that's not the issue. But I'm not seeing the issue that you're speaking of though - the element goes the same speed whether the spacer is 900vh or 100vh to me.

Link to comment
Share on other sites

Sorry that's because I left .offsetY in the code. I changed it back to the original code:

end: () => container.scrollWidth - document.documentElement.clientWidth + container.offsetWidth}

Now you should be able to see the issue i'm talking about.

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.

×