Jump to content
Search Community

Horizontal scroll with multiples and different child animation

Mauro.ie31 test
Moderator Tag

Recommended Posts

Hello,

I'm using Gsap Scroll Trigger with my all my entire pages.
I have multiples sections.

Every section has different child element.

I want to know if it's possible to handle specific part of sections (for example, 15% of a specific one, the same as I do with normal vertical scroll ).

But I don't know how to do it and I don't know if it's possible.

Praticale example:

In the codepen i want something like this this:

Apply different animations on different child element of the same parent (.red) relatively to the actual parent that is in the viewport.

Thanks for your help

 gsap.from('#text-1', {
                opacity: 1,
                x: -300,
                
                scrollTrigger: {
                    trigger: '.red',
                    start: '80% 50%',
                    end: '+=500',
                  scrub: 1,
                },
            });
 
 gsap.from('#text-2', {
                opacity: 1,
                y: 300,
                rotate: -90,
                scrollTrigger: {
                    trigger: '.red',
                    start: '60% 50%',
                    end: '+=500',
                  scrub: 1,
                },
            });

See the Pen vYXBdKa by mauroie31 (@mauroie31) on CodePen

Link to comment
Share on other sites

 

*** UPDATE with GSAP 3.8 ***

 

Since I have redirected to this post in quite a few threads, I just wanted to update it.

 

Things have become a lot easier with GSAP 3.8, which brings the containerAnimation property that lets you handle your ScrollTriggers in a much more intuitive way e.g. in fake-horizontal scroll scenarios like these.

 

The calculations explained below will not be neccessary anymore with this new feature if you want to trigger animations on invividual sections/elements in a scenario as such. They might still be relevant e.g. for scrollTo functionality.

 

 

containerAnimation Tween | Timeline - A popular effect is to create horizontally-moving sections that are tied to vertical scrolling but since that horizontal movement isn't a native scroll, a regular ScrollTrigger can't know when, for example, an element comes into view horizontally, so you must tell ScrollTrigger to monitor the container's [horizontal] animation to know when to trigger, like containerAnimation: yourTween. See a 

See the Pen 9be5d371346765a8c9a426e8f65f1cea by GreenSock (@GreenSock) on CodePen

 and more information here. Caveats: the container's animation must use a linear ease ( ease: "none"). Also, pinning and snapping aren't available on containerAnimation-based ScrollTriggers. You should avoid animating the trigger element horizontally or if you do, just offset the start/end values according to how far you're animating the trigger. 

 

See the Pen ae79b09682c6c1e5c158156f47bda88a by akapowl (@akapowl) on CodePen

 

 

 

 

 

 

 

*** Original Post starts here ***

 

On 12/2/2020 at 1:05 AM, Mauro.ie31 said:

But I don't know how to do it and I don't know if it's possible.

 

Hey @Mauro.ie31

 

Of course you could do that, but for achieving that, you'd have to do some calculations yourself  for detecting when the section you want to adress, actually comes into viewport - and if I am not totally misunderstanding and/or overcomplicating things (someone please chip in if I am/do) , there is one problem in all of that, that will make those calculations sort of complex (not really in a mathematic way - but more in their length).

 

 

 

Let me explain from the start:

 

In this following codepen-demo, forEach .panel/section, I set up a ScrollTrigger that is supposed to toggle the 'active class' when the sections left border hits the horizontal center of the screen - calculated by the offsetLeft of that section minus the window's innerWidth devided by 2.

 

sections.forEach((sct, i) => {
  
  ScrollTrigger.create({
    trigger: 'body',
    start: 'top top-=' + (sct.offsetLeft - window.innerWidth/2),
    end: '+=' + sct.offsetWidth,
    toggleClass: {targets: sct, className: "active"},   
  })
  
});

 

See the Pen dab3fba5dadb5e3fb8837f7151bbbfa4 by akapowl (@akapowl) on CodePen

 

 

 

Sounds pretty straight forward at first, right?

 

Well, if you look closely (in dev-tools console - and since the edit also by looking at the color of the 'headlines') it actually doesn't work the way you'd expect. Already for the red panel, the class gets toggles a bit before it hits the center, and that offset appears to be piling/become even bigger for every other section.  

 

 

In the following demo, I changed the xPercent of the fake-horizontal-scroll-tween to

 

xPercent: -100 * (sections.length)

 

to clear up, why the problem above occurs 

 

See the Pen 8848cf9720220da491674e29b5dc06d5 by akapowl (@akapowl) on CodePen

 

 

 

Of course, this is not the behaviour you want because if you scroll to the end, the last section will be moving completely off screen to the left.

But what you'll notice, is that the ScrollTriggers for toggling the class now will fire as you'd expect them to; when their left border hits the horizontal center of the screen.

 

So the problem in all of that is, that for the originally wanted behaviour of this fake-horizontal-scroll, the tween on the x-axis has to have a shorter distance (by one section/one window-width) than the actual 'duration' of the ScrollTrigger that is hooked up to that tween. That creates an offset, that you would have to consider for all the calculations you'd be making on the individual ScrollTriggers for each section.

 

 

 

See the Pen 08ad92ee05b35dd80d8c41cbfbcd416d by akapowl (@akapowl) on CodePen

 

 

 

The offset occuring translates to the 'duration' of that fake-horizontal-ScrollTrigger devided by the distance you are tweening on the x-Axis.

Basically you'd have to multiply the intital values for those individual ScrollTriggers with that offset/quotient and things would work as expected.

 

 

But you see, that the calculations for what you want to achieve can get quite complex (just meaning long) and not trivial to wrap your head around because of that. It would always be easier to simply just use real native horizontal scrolling for something like this, instead of faking the horizontal scroll.

 

 

I really hope this all makes sense, and I am not overcomplicating here. If I do, I hope someone will correct me on this.

 

Nonetheless, I also hope this was somewhat helpful.

 

Cheers.

Paul

 

 

 

Edit:

 

If you were to use some sort of navigation with scrollTo-functionality in a scenario like this (where the amount of x-translation and the scroll-amount of the ScrollTrigger don't match up) you would of course also have to include that offset into your calculations for where to scroll to. That could look something like this then:

 

See the Pen a82e21f8d9c7bce0059159ced099666d by akapowl (@akapowl) on CodePen

 

  • Like 4
Link to comment
Share on other sites

  • 2 weeks later...

I'm sorry but I'm not able to resolve this.

I'm tryng to locate the first start of each section.

Suppose I have three sections, #Section1, #Section2, #Section3.

I want to locate the start and the end of each section,  so I could apply gsap transition in the interval from the start and the end of each section.

 

 gsap.registerPlugin(ScrollTrigger);


    const sections = gsap.utils.toArray(".panel");
    let maxWidth = 0;
    let index = 0;
    const getMaxWidth = () => {
      maxWidth = 0;
      sections.forEach((section) => {
        index++;
        switch (index) {
          case 1:
            section1Width = section.offsetWidth;
            break;
          case 2:
            section2Width = section.offsetWidth;

            break;
          case 3:
            section3Width = section.offsetWidth;
            break;
        
        }
        maxWidth += section.offsetWidth;

      });

So, after, I defined the variables start and end of each section:

 section1Start = 0;
      section1End = section1Width;
      console.log('Sezione 1 Inizio: ' + section1Start + ' Sezione 1 Fine: ' + section1End )

      
      section2Start = section1End;
      section2End = section2Start + section2Width;
      console.log('Sezione 2 Inizio: ' + section2Start + ' Sezione 2 Fine: ' + section2End);

      section3Start = section2End;
      section3End = section3Start + section3Width;
      console.log('Sezione 3 Inizio: ' + section3Start + ' Sezione 3 Fine: ' + section3End);

Then, I do a transform to #section 1

 

    
    gsap.to("#section1", {
      scrollTrigger: {
        trigger: "body", // elemento oggetto dello scrolltrigger
      //  start: () => "0 -" + (document.querySelector(".container-scroll").offsetWidth / (sections.length - 1) * 1),
        start: "top-=0",

        end: "+=" +  section1End,
        scrub: true,
        markers: true,
        onUpdate: self => {
          console.log(self.progress);

        },      },
      backgroundColor: "#000",
      ease: "none"
    });
    

But actually the end of the gsap transform is more long than the actual width. I don't know where are my mistake becase the calculations are correct.

Where am I wrong?

Link to comment
Share on other sites

56 minutes ago, Mauro.ie31 said:

But actually the end of the gsap transform is more long than the actual width. I don't know where are my mistake becase the calculations are correct.

 

Hey @Mauro.ie31

 

It looks to me, like for none of the variables you are setting up above, you are considering the 'offset' I described in detail in my post above. 

 

 

On 12/2/2020 at 12:10 PM, akapowl said:

So the problem in all of that is, that for the originally wanted behaviour of this fake-horizontal-scroll, the tween on the x-axis has to have a shorter distance (by one section/one window-width) than the actual 'duration' of the ScrollTrigger that is hooked up to that tween. That creates an offset, that you would have to consider for all the calculations you'd be making on the individual ScrollTriggers for each section.

 

You will have to take that 'offset' into consideration for each of your starts and ends of each of your ScrollTriggers for each section.

 

For everything that you want to consider horizontally you will have to make up for the discrepancy between the duration of the fake-horizontal-tween and the actual 'duration' of the scroll . This is the key-factor to consider for all your starts and ends

 

* (document.querySelector(".container").offsetWidth/(sct.offsetWidth * (sections.length - 1))

 

See the last pen I posted above, and how it is applied there.

 

I know that it is complicated, but I actually don't know how to better describe it, than the way I already did.

 

  • Like 3
Link to comment
Share on other sites

On 12/14/2020 at 7:38 PM, akapowl said:

 

Hey @Mauro.ie31

 

It looks to me, like for none of the variables you are setting up above, you are considering the 'offset' I described in detail in my post above. 

 

 

 

You will have to take that 'offset' into consideration for each of your starts and ends of each of your ScrollTriggers for each section.

 

For everything that you want to consider horizontally you will have to make up for the discrepancy between the duration of the fake-horizontal-tween and the actual 'duration' of the scroll . This is the key-factor to consider for all your starts and ends

 



* (document.querySelector(".container").offsetWidth/(sct.offsetWidth * (sections.length - 1))

 

See the last pen I posted above, and how it is applied there.

 

I know that it is complicated, but I actually don't know how to better describe it, than the way I already did.

 

I'm sorry but it doesn't work.

I have seven section with different width.

For example:
- Section 1 has 500vw,
- Section2 has 200vw,
- Section 3 has 200vw,
 etc.

If I do this:
- For the first section is ok, because it starts from zero.

But from the second :
 

      gsap.timeline({
        scrollTrigger: {
          trigger: "body",
          //6 è il numero delle sezioni totali - 1
          start: 'top top-=' + (section2OffsetLeft - window.innerWidth / 2) * (containerWidth / (section2OffsetWidth * (6))) ,
          end: '+=' + section2OffsetWidth * (maxWidth / (section2OffsetWidth * (6))),
          scrub: true,
          onUpdate: self => {
            console.log('second section');
            console.log(self.progress);
        },
        },
        // backgroundColor: "red",
        ease: "none"
      })

The timeline will trigger very very far from the actual point.

Is that because the width of each section are different?

Thanks a lot you are really helpful.

Link to comment
Share on other sites

On 12/16/2020 at 2:42 AM, Mauro.ie31 said:

Sorry agait, but what you intend for "real native horizontal scrolling"?

 

With native horizontal scrolling I meant something like this 

 

See the Pen dfddf67657d002d25d722729a67582c3 by akapowl (@akapowl) on CodePen

 

 

And I actually just realized that what I wrote above might not even be relevant for you, because there are quite a few different approaches on how to achieve the fake-horizontal scrolling. So it would be great, if you could provide a demo codepen of how you do that in the first place. It would make it easier to help.

 

I guess each approach has its pros and cons, but maybe you could consider changing your setup, so what you want to achieve becomes a bit easier to do.

 

This pen here for example handles the pinning and the x-translation of each section in seperate ScrollTriggers. The pinning happens on the container itself, but to get it working, you'd need an extra wrapper around the sections to act as the trigger-element for the ScrollTriggers of each section. In this scenario it might be quite a bit easier to wrap your head around  animating things depending on where the sections are.

 

See the Pen 0914664ede434e5602ff550292e19902 by akapowl (@akapowl) on CodePen

 

  • Like 4
Link to comment
Share on other sites

9 hours ago, akapowl said:

 

With native horizontal scrolling I meant something like this 

 

 

 

 

 

And I actually just realized that what I wrote above might not even be relevant for you, because there are quite a few different approaches on how to achieve the fake-horizontal scrolling. So it would be great, if you could provide a demo codepen of how you do that in the first place. It would make it easier to help.

 

I guess each approach has its pros and cons, but maybe you could consider changing your setup, so what you want to achieve becomes a bit easier to do.

 

This pen here for example translates each section to the left on the x-axis for the amount of the whole container-scrollWidth instead of the xPercent of the section itself multiplied by its index. The pinning happens on the container itself, but to get it working, you'd need an extra wrapper around the sections to act as the trigger-element. But in this scenario it is quite a bit easier to wrap your head around  animating things depending on where the sections are.

 

 

 

 

You are really great.

Thanks for your help

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