Jump to content
GreenSock

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

Scrolling list with Image in horizontally scrolling sections

Recommended Posts

 

Hi,

 

I've been experimenting with GSAP and I'm really excited. But from time to time I don't get any further, because unfortunately I don't yet understand all the mechanisms and parameters and I hope you have a tip for me.

 

I want to achieve the following structure:

 

4 Sections scroll horizontally.

 

The 3rd section stops and shows a text element list on the left and a graphic on the right.

 

The user should navigate through the list by scrolling.

 

The list moves up (disappears) and the next text list element is activated (opacity 1) and shows a different image on the right side. The list should not have a limited number of list text elements. This will be dynamically expanded later. If the last list text element is active, the user scrolls further to the right into the next section.

 

I saw this on another website but unfortunately the mechanism wasn't built with GSAP so I wanted to see if it could be replicated. A Gif is attached. The background change in the animation is not necessary.

 

561699901_May-11-202215-34-02.gif.efd3010884edba41a89d585f54c63ed6.gif

Can I do this with GSAP?

 

Thank you for your help :) 

 

See the Pen KKQMgZJ by dkx (@dkx) on CodePen

Link to comment
Share on other sites

Ok i can now add the Gif example in post before :) 

Link to comment
Share on other sites

Hi DK7,

 

It's best to think in terms of animations instead of scrolling. ScrollTrigger is just an animation controller, so you need to solve the animation problem before worrying about scrolling or anything else that ScrollTrigger does.

 

You basically described everything you need to do for your timeline.

  1. Animate to the 3rd section
  2. Animate stuff in inside the 3rd section vertically
  3. Animate to the 4th section

 

 

 

  • Like 1
Link to comment
Share on other sites

17 minutes ago, OSUblake said:

Hi DK7,

 

It's best to think in terms of animations instead of scrolling. ScrollTrigger is just an animation controller, so you need to solve the animation problem before worrying about scrolling or anything else that ScrollTrigger does.

 

You basically described everything you need to do for your timeline.

  1. Animate to the 3rd section
  2. Animate stuff in inside the 3rd section vertically
  3. Animate to the 4th section

 

 

 

Hi @OSUblake,

 

thank you very much for your quick answer.

 

I think I might have described it wrong.

 

The animations are supposed to be triggered by scrolling.

 

As soon as the user enters this section 3, the further downward scrolling should jump from link to link (i.e. vertically) and then horizontally at the end to the next section.

 

I had already found out that theoretically I could simply make one section under the other for each text and then scroll through them. But then the other texts in the list above and below are missing in the visible area.

 

I hope I could explain that a little better now.

 

I've only been testing with GSAP for 2 days. I've only used gsap.to so far. The timelines are completely new to me. Although I had understood that timelines run through when triggered, right? That would mean that the user enters section 3 and then the links go through automatically, right?

Or can I also control the timeline based on the scroll positions?

 

Thank you very much for your help! :) 

 

 

Link to comment
Share on other sites

27 minutes ago, DK7 said:

The animations are supposed to be triggered by scrolling.

 

I know, but that's not important right now. Just focus on making the timeline. That's where a lot of new people mess up. They are approaching everything as if it's a scrolling problem, when in reality it's an animation problem. A timeline will work the same regardless of it's hooked up to ScrollTrigger on not.

 

ScrollTrigger will scrub through a timeline just like everything else. Just think of ScrollTrigger as being like GSDevTools that you control with the scroll position.

 

But again, don't focus on the scrolling part right now. If you make a timeline that does what I described below, I guarantee you it will work once you hook it up to ScrollTrigger.

 

55 minutes ago, OSUblake said:
  • Animate to the 3rd section
  • Animate stuff in inside the 3rd section vertically
  • Animate to the 4th section

 

  • Like 3
Link to comment
Share on other sites

Here's just a quick demo. I'm just animating scale on the 3rd slide to show that is where you do the animations for the vertical movement.

 

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

  • Like 5
Link to comment
Share on other sites

30 minutes ago, OSUblake said:

Here's just a quick demo. I'm just animating scale on the 3rd slide to show that is where you do the animations for the vertical movement.

 

 

 

That was exactly my problem! I couldn't understand how to pin Section 3 and then animate in it.

Thank you very much for the example it really helps me a lot.

 

Now I can continue and test here :)

  • Like 2
Link to comment
Share on other sites

Hi @OSUblake and @Cassie,

 

i need help please 🤯

 

In the last 2 days I've been studying the examples and common error pages of GSAP and unfortunately I can't get any further.

That's because I still don't understand some basic things about GSAP.

 

Can you explain this to me in a little more detail?

 

Here is my current status. How can I insert a code pen in an answer here ^^

See the Pen JjpRgQY by dkx (@dkx) on CodePen

 

1. the original horizontal scroll effect was performed by this code:

let sections = gsap.utils.toArray(".slide");

let scrollTween = gsap.to(sections, {
    xPercent: -100 * (sections.length - 1),
    ease: "none",
    scrollTrigger: {
      trigger: ".main-container",
      pin: true,
      scrub: 0.1,
      ends: "+=3000"
    }
  });

@OSUblake... replaced this with a timeline:

let sections = gsap.utils.toArray(".slide");

let tl = gsap.timeline({
  scrollTrigger: {
      trigger: ".main-container",
      pin: true,
      scrub: 0.1,
      end: "+=2000"
    }
})
.to(sections, {
  xPercent: -100 * 2,
  ease: "none",
});

tl.to(".list-left", {
  scale: 0.5,
  yo-yo: true,
  repeat: 1
});
tl.to(sections, {
  xPercent: -100 * (sections.length - 1),
  ease: "none"
});

I'm trying to understand this code now 🤔

The timeline and a scroll trigger for the complete content container of all horizontal sections are created first:

let sections = gsap.utils.toArray(".slide");

let tl = gsap.timeline({
  scrollTrigger: {
      trigger: ".main-container",
      pin: true,
      scrub: 0.1,
      end: "+=2000"
    }
})

but why does this code set the 3rd section pinned? If I replace the * 2 with a * 3, the 4th section is pinned. I just don't get the point no matter how hard I try to understand. Doesn't the code actually mean that each section gets an xPercent value of -100 * 2, i.e. -200?

 

.to(sections, {
  xPercent: -100 * 2,
  ease: "none",
});

After that comes this code:

tl.to(".list-left", {
scale: 0.5,
yo-yo: true,
repeat: 1
});

but why does a .to step have to come before tl.to(sections...) so that section 3 is pinned? If I remove this .to animation step, then the section does not remain fixed / pinned?  I can also change this but I just can't remove it.

 

I think my problem is, since GSAP is still totally new, that I don't yet have an overview of the context of the animations.

 

My original plan, the scrollable list, is slowly but surely becoming functional.

 

However, two things are not entirely clear to me:
 

1. Does the code I wrote make sense for this animation, or am I making it unnecessarily difficult? This question is important for me to assess whether I understand things correctly or not :) 
 

2. Why is the "onEnter" callback triggered but not "onEnterBack" when scrolling back?
 

3. I just saw through the codepen that if the view is not like in my local test environment (1920x1080px monitor) then the scroll triggers don't work properly. Is it correct to work with % values here? How to fix this automatically in GSAP?

 

GSAP is really an exciting topic! I'm looking forward to the day when I understand the technology behind it :D 

 

Thank you for your time and help 🙏

 

 

 

Link to comment
Share on other sites

2 hours ago, DK7 said:

but why does this code set the 3rd section pinned? If I replace the * 2 with a * 3, the 4th section is pinned. I just don't get the point no matter how hard I try to understand. Doesn't the code actually mean that each section gets an xPercent value of -100 * 2, i.e. -200?

 

I don't how familiar you are with arrays, but knowing that arrays are zero-based is key to understanding all that. Zero-based means the first item has an index of 0. So the second item would have an index of 1, the third item would have an index of 2, and so on.

 

And think about it in terms of math. How many screen widths is the first panel away from the viewport? It's already in view, so that would be 0. The second panel is 1 screen width away, the third panel is 2 screen widths away and so on.

 

And that's why you'll commonly see this calculation to do horizontal effects.

xPercent: -100 * (sections.length - 1),

 

We subtract 1 from the length because length is not zero-based. So if there are 5 sections, i.e. the array length, then the last section will have an index of 4. Yes, it can be confusing, but that's just how it is.

 

2 hours ago, DK7 said:

but why does a .to step have to come before tl.to(sections...) so that section 3 is pinned?

 

First off, that section is not being pinned. What is being pinned is the trigger you set here.

 

let tl = gsap.timeline({
  scrollTrigger: {
      trigger: ".main-container", // this is what gets pinned
      pin: true,
      scrub: 0.1,
      end: "+=2000"
    }
})

 

Throughout this thread, I've been trying to make it a point that you need to approach it as an animation problem and not a scrolling problem. 

 

So here's essentially what a horizontal animation would look like if you could scale it down. The red box is meant to represent the viewport of your screen.

 

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

 

And ScrollTrigger is very similar to GSDDevTools in that it can scrub animations. If scrubbing that animation looks fine in GSDevTools, it will look the same if we hook it up to ScrollTrigger.

 

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

 

So I would suggest trying to make a timeline just like I did. If it works without ScrollTrigger, it will work with it. That's a hint that you should not have any nested ScrollTriggers inside your timeline, like I see here.

 

tl.to('.list-left ul', {
  scrollTrigger: { // !!! you should never have a nested ScrollTrigger
      trigger: '.list-left ul',
      start: "83% center",
      scrub: true,
      markers: true,
  },
  ...
})

 

See the most Common ScrollTrigger Mistakes for more information.

 

 

And for the images, I would not change the src as you can't animate that. To do a crossfade you need to have all the images inside the DOM, and then absolutely positioned on top of each other.

 

  • Like 5
Link to comment
Share on other sites

22 hours ago, OSUblake said:

 

I don't how familiar you are with arrays, but knowing that arrays are zero-based is key to understanding all that. Zero-based means the first item has an index of 0. So the second item would have an index of 1, the third item would have an index of 2, and so on.

 

And think about it in terms of math. How many screen widths is the first panel away from the viewport? It's already in view, so that would be 0. The second panel is 1 screen width away, the third panel is 2 screen widths away and so on.

 

And that's why you'll commonly see this calculation to do horizontal effects.

xPercent: -100 * (sections.length - 1),

 

We subtract 1 from the length because length is not zero-based. So if there are 5 sections, i.e. the array length, then the last section will have an index of 4. Yes, it can be confusing, but that's just how it is.

 

Aaaah ok now I understand the meaning behind it! Thank you for the detailed explanation!

 

And through the "Sections" array, all the sections stored in the array get the .to() right?

 

.to(sections, {
xPercent: -100 * 2,
ease: "none",
});

In the end, you could also write it like this with 5 sections:

 

tl.to(sections, {
xPercent: -100 * (5 - 1),
ease: "none"
});

and this .to() is also given to all sections. So that would actually be xPercent: -100 * 4 right?

 

But why does the timeline still have to animate ".left-side" so that the sections scroll horizontally? I don't quite understand that yet?

 

We have:

 

let sections = gsap.utils.toArray(".slide");

let tl = gsap.timeline({
  scrollTrigger: {
      trigger: ".main-container",
      pin: true,
      scrub: 0.1,
      end: "+=2000"
    }
})
.to(sections, {
  xPercent: -100 * 2,
  ease: "none",
});

tl.to(".list-left", {
  scale: 0.5,
  yo-yo: true,
  repeat: 1
});
tl.to(sections, {
  xPercent: -100 * (sections.length - 1),
  ease: "none"
});

 

For the sake of clarity, a short summary:

let tl = gsap.timeline

.to sections



tl

.to list-left

.to sections

 

".to list-left" could actually be deleted:

let tl = gsap.timeline

.to sections



tl

.to sections

but then you could actually do it that way, or doesn't that work?

let tl = gsap.timeline

.to sections

.to sections

I think it is important for me as a beginner to understand the order.

If I create a timeline and this is already assigned a .to() at the beginning, like this:

 

let tl = gsap.timeline
.to.... 1

 

what happens if I add something to this timeline later? So that's how:

let tl = gsap.timeline
.to... 1

.......
.......
.......

tl
.to... 2
.to... 3
.to... 4

Then .to 1 is executed first and then .to 2 3 4, isn't it?

 

And what I also noticed, some .to() only work if I use "gsap.to" instead of "tl.to".

 

Can you briefly explain the difference to me? That would be great!

 

Is "gsap" a kind of global timeline that encompasses everything? But creating a new timeline with:

 

let tl = gsap.timeline({
  scrollTrigger: {
      trigger: ".main-container",
      pin: true,
      scrub: 0.1,
      end: "+=2000"
    }
})

 

is then only from or for the scroll trigger element ".main-container"?

 

 

22 hours ago, OSUblake said:

 

 

First off, that section is not being pinned. What is being pinned is the trigger you set here.

 

let tl = gsap.timeline({
  scrollTrigger: {
      trigger: ".main-container", // this is what gets pinned
      pin: true,
      scrub: 0.1,
      end: "+=2000"
    }
})

 

Throughout this thread, I've been trying to make it a point that you need to approach it as an animation problem and not a scrolling problem. 

 

Ok I think I'm confusing the meaning of pinned. I thought pinned would be like e.g. in CSS fixed. The element is then positioned in a fixed manner.

But fixed elements, for example, don't work at all within horizontal scroll areas, as I've noticed, right?

 

I was able to use

 

CSS:

.logo{

  position:fixed;

  left:20px;

  top:20px;

}

place a logo at the top left and all sections behind it are scrolled horizontally as normal.

 

BUT I can't do

CSS:

.burgernav{

  position:fixed;

  right:20px;

  top 20px;

}

to place a burger menu at the top right.

 

No matter what I try, the element stays invisible. Why is that and how can I do that?

 

 

22 hours ago, OSUblake said:

So here's essentially what a horizontal animation would look like if you could scale it down. The red box is meant to represent the viewport of your screen.

 

 

And ScrollTrigger is very similar to GSDDevTools in that it can scrub animations. If scrubbing that animation looks fine in GSDevTools, it will look the same if we hook it up to ScrollTrigger.

 

 

Ok the code is up to "gsap.registerPlugin(GSDevTools);" & "GSDevTools.create();" identical in these examples right?

I haven't tried GSDevTools yet ^^

 

 

22 hours ago, OSUblake said:

 

So I would suggest trying to make a timeline just like I did. If it works without ScrollTrigger, it will work with it.

 

Yes, I really want to do it the way you do -  I'm LEARNING diligently every beginning is difficult :D

 

If I understood your hint correctly, then I actually always have to build a timeline that plays all animations of the entire page one after the other when it should be a horizontal scroll mechanism. Only when everything looks so good automatically, i.e. when I press play or the timeline starts by itself, only then do I add scroll triggers in the code at the end? 

 

 

 

 

22 hours ago, OSUblake said:

 

That's a hint that you should not have any nested ScrollTriggers inside your timeline, like I see here.

 

tl.to('.list-left ul', {
  scrollTrigger: { // !!! you should never have a nested ScrollTrigger
      trigger: '.list-left ul',
      start: "83% center",
      scrub: true,
      markers: true,
  },
  ...
})

 

That's an important tip thank you!

 

 

22 hours ago, OSUblake said:

See the most Common ScrollTrigger Mistakes for more information.

 

 

Yes, thanks! I've read it all several times and made my own "important list" of things I'm sure I'll need again at some point :D 

 

22 hours ago, OSUblake said:

And for the images, I would not change the src as you can't animate that. To do a crossfade you need to have all the images inside the DOM, and then absolutely positioned on top of each other.

 

 

I would like to do that, but since the images should have background-size: cover via CSS, so that they always fill the entire container responsively (60% .right-side), I have to change the images via CSS. Unfortunately, IMG only supports "workarounds" which are not compatible with all browsers. But thanks for the tip!

 

I apologize for my many questions and thank you for your patience and time! As a beginner to new techniques, I can only learn things from a pro like you. And I'm glad that you are doing such a great job here in the forum and that you are taking the time to help!

 

Thank you very much 🙏

 

 

Link to comment
Share on other sites

There are a lot of questions here. Going from your questions about the difference between gsap.to and tl.to it seems like you're lacking in some core understanding.

 

gsap.to is a tween and tl.to is for adding a tween to a timeline. These are two core concepts that are very important to understand before progressing further into other plugins.

This is a great video for anyone getting started with GSAP. Can I suggest you take some time to watch it and then if you still have questions, pop back and we'll do our best to explain.

 

Getting Started with GSAP from GreenSock on Vimeo.



Additionally

On 5/14/2022 at 6:39 PM, DK7 said:

I would like to do that, but since the images should have background-size: cover via CSS, so that they always fill the entire container responsively (60% .right-side), I have to change the images via CSS. Unfortunately, IMG only supports "workarounds" which are not compatible with all browsers. But thanks for the tip!

 

That's fine - all you have to do is put multiple divs into the HTML - as long as you have multiple elements you can crossfade them.
 

  • Like 2
Link to comment
Share on other sites

On 5/15/2022 at 12:31 PM, Cassie said:

There are a lot of questions here. Going from your questions about the difference between gsap.to and tl.to it seems like you're lacking in some core understanding.

 

gsap.to is a tween and tl.to is for adding a tween to a timeline. These are two core concepts that are very important to understand before progressing further into other plugins.

This is a great video for anyone getting started with GSAP. Can I suggest you take some time to watch it and then if you still have questions, pop back and we'll do our best to explain.

 

Getting Started with GSAP from GreenSock on Vimeo.



Additionally

 

That's fine - all you have to do is put multiple divs into the HTML - as long as you have multiple elements you can crossfade them.
 

Hi @Cassie,

thank you very much for your help! The video was also very helpful :) I've watched it a few times now so that things stay in my memory :D 

 

  • Like 1
Link to comment
Share on other sites

Ah so glad to hear it was helpful. Awesome.

And don't worry about keeping it in your memory. It's very normal to have to refer to the documentation. The important thing is to have a broad understanding of how everything fits together - then you can pop back to check out specifics.

This cheatsheet may be useful too.

https://greensock.com/cheatsheet/

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