Jump to content
Search Community

How to pin div in a full horizontal scroll

Pauline Brothier test
Moderator Tag

Go to solution Solved by akapowl,

Recommended Posts

Hello ! 


I'm new with scrollTrigger and I don't understand how I can pin elements inside my horizontal scroll section. 
For example, in this codepen :  I would like the scroll to stop when the number 3 (grey div)  "touch" the left side of the screen.

And then the number 4 scroll above the number 3 section and the classic horizontal scroll continue. 

I think it's possible, I hope, but I don't understand how to make it. 

 

I hope my issue is clear, and someone could help me on it. 

 

Thanks :)

See the Pen MWjeqdb by PaulettePaillette (@PaulettePaillette) on CodePen

Link to comment
Share on other sites

 

Hey @Pauline Brothier - welcome to the forums :)

 

4 hours ago, Pauline Brothier said:

but on my website (http://dev.bklt.fr/ggr/agence.html), is super fast.

 

The problem on your website is, that for the x-translation you use the scrollWidth of the container, whereas for the end of the ScrollTrigger, you use the offsetWidth - which basically means the width that the container takes space in the window. So your 'scroll-duration' here is just a window's width. You could try changing it to the scrollWidth of your container instead, see if that changes anything, and adjust it to your needs.

 

 

4 hours ago, Pauline Brothier said:

I would like the scroll to stop when the number 3 (grey div)  "touch" the left side of the screen.

 

I don't think that would be too trivial to get to, and you would probably have to change your setup (at least for the ScrollTrigger) quite a bit to get it working.

 

The thing is, that you are not naturally scrolling horizontally, so ScrollTrigger's pinning is not something that would work. So instead you would probably have to animate each section to the left individually, and do the calculations individually for when you want the animation of that one section to stop (and maybe start again). I myself can not think of an easier way of how to do that now - maybe someone else will, though.

 

It would probably be easier, if you were to be able/willing to use natural horizontal scrolling - but I get, that depending on the exact scenario you want this to happen in, that might not be a solution to go with at all.

 

Anyways, hope this helps.

 

Cheers,

Paul

  • Like 3
Link to comment
Share on other sites

  • Solution

 

Alright,

as always, to get something like that working, it is not one solution fits all, so you probably can not rely on the following demo to be working in every imaginable scenario. But I was curious myself on how get something like what you described working and came up with this following little concept.

 

It works properly ( even after resizes ), but if you wanted to do things differently, you would have to apply the changes yourself and figure out a way to get it running in you scenario, if my demo doesn't work for you. This is just for demonstration purposes of how to possibly achieve what you intended.

 

For example, I added margins to space out the elements - and added a wrapper around the elements, that it my demo serves as the trigger element for each of the .thumbnail-ScrollTriggers. The wrapper has a set width ( which equals to the width of all those elements plus their margins ) - That you would definitely have to adjust to your scenario. It may look wild, but it actually makes sense. Also note, that I went away from using display: flex for the aligning of the .thumbnails, because it kept messing with the widths of those elements, so instead I went to use display: inline-block and float left on the .thumbnails themselves. There are quite a few other changes in the CSS, but it would be too much to adrress every single one of them now.

 

For the ScrollTriggers themselves:

I use one trigger for the pinning of the .container - that one is what makes the whole thing scrollable. Since I had it there already, whithout doing anything else, I thought it would be a good idea to also leverage it for animating that fake-scrollbar/scrollindicator that you had commented out in your demo.

 

I added extra individual ScrollTriggers for each of the thumbnails. 

Those without fake-pinning essentially behave the same, as you had initially  for your whole container - but here instead it happens for each section individually. For those with fake-pinning, I added an extra function, that calculates their total-width to move (used for their x-translation, and the end of the ScrollTrigger) that takes into account all previous thumbnails with their widths and margins.

 

It may not be perfect, but it works decently.

 

And as you see, this is not the most trivial thing to realize - unless I am overcomplicating, which I might be.

 

This doesn't take into account though, that at one point, you might want to 'unpin' a thumbnail again, but that could be calculated too for each element.

 

Also, what you might notice on this demo:

depending on how fast you scroll, there will be a larger 'offset' to when the fake-pinning happens. I think, this is soleley just related to how the scrub works - you won't see an offset like that with the scrub set to true instead of a different value. So if you wanted to get rid of that offset, you'd have to use scrub:true and if you still wanted the whole thing to be 'smooth' you then would also have to use a smooth-scrolling library on top of that.

 

With all that being said, here is the demo I was talking about all along

 

See the Pen 59f35078bb8ca75e734aa43a4761414a by akapowl (@akapowl) on CodePen

 

 

I actually quite like the idea, it allows for some neat stacking effects, too.

 

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

 

 

Anyways, I know, the setup is much different from what you have posted above, and it might be a bit tricky to wrap your head around all this, but I hope this still helps at least convey an idea, of how to get to what exactly you need.

 

Cheers,

Paul

 

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

  • 3 months later...

@akapowl Awesome solution! Thanks so much for posting a demo, it's been really helpful to learn from.

 

I've been trying to implement ScrollTo into your demo, using nav links as anchor links to each section - same functionality as in this 

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

 and struggling a little bit lol... I was hoping you might be able to give me some direction please? ?

 

I have anchor links set up, just having trouble with getting the scroll container to scroll to the selected section. 

 

Cheers,

Dan

  • Thanks 1
Link to comment
Share on other sites

Hi @akapowl,

 

Thanks for the welcome and taking the time to reply, I really appreciate it!

 

I've had crack at implementing scroll to as in your demo above, but it seems my issue is with ScrollTo. On click of an anchor item, I'm getting a console warning "scrollTo target doesn't exist. Using 0". I've put together a basic codepen, if possible would you mind please having a quick look to see what I'm doing wrong? ?

 

Thanks so much for all your help.

 

Cheers,

 

See the Pen JjEpJem by tracta_nz (@tracta_nz) on CodePen

 

 

Link to comment
Share on other sites

31 minutes ago, tractaNZ said:

I've put together a basic codepen, if possible would you mind please having a quick look to see what I'm doing wrong? ?

 

Sure;

Since you appear to be using locomotive-scroll, GSAP's ScrollTo-Plugin won't work here because of the way that smooth-scrolling library works.

 

You will have to use locomotive-scroll's own .scrollTo method.

 

Check loco-scroll's documentation on GitHub for more information.

 

 

 

Also it looks like you are mixing jQuery methods with vanilla JS methods.

 

When you store your panelsSection in a variable like this

 

//anchor links
var panelsSection = $(".scroll-container");

 

in combination with the rest of the code for the scrollTo now your containerOffset returns 'NaN'.

 

So you will have to adjust the rest of your code for the scrollTo to work with the jQuery way - or just stick to vanilla JS for getting the panelsSection as in the example

 

//anchor links
var panelsSection = document.querySelector(".scroll-container");

 

See the Pen 5eeff1c5e2fb29c59f8230844a72d0ab by akapowl (@akapowl) on CodePen

 

 

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

Hi @akapowl,

 

I've been playing around with your original anchor scrolling pen. I'm trying to implement anchors to content within the panels as well as the having nav anchors to each section. 

 

If you wouldn't mind having a look in the pen below, you'll see I've added a child anchor within Panel 3 called 3 Inner. Though on click of the nav item Panel 3 Inner the child anchor is offset to the right, rather than to the left like the parent panel anchors

 

See the Pen MWJBJdY by tracta_nz (@tracta_nz) on CodePen

 

If you have any advice I would really appreciate it :)

 

Cheers,

Link to comment
Share on other sites

5 hours ago, tractaNZ said:

Though on click of the nav item Panel 3 Inner the child anchor is offset to the right, rather than to the left like the parent panel anchors

 

The logic for the scrollTo is not built for respecting child-elements of the panels but only the panels themselves so far, so you'd have to incorporate some logic that would respect that.

 

You could e.g. set up an if statement in which you check wether the e.target.getAttribute("href") has "inner" at its end.

 

If it does, set the containerOffset to the panel's offsetTop plus the targetElement's offsetLeft plus the targetElement's parent's offsetLeft (because for that case, your targetElement is not the panel itself anymor but the pannel's inner).

 

Else, use the calculations as before.

 

  • Thanks 1
Link to comment
Share on other sites

 

Good job :) 

 

With the afore-mentioned if statement you could spare some code, though. Maybe something like this

 

if(e.target.getAttribute("href").slice(9) === 'inner') {
  containerOffset = panelsSection.parentElement.offsetTop + targetElem.parentElement.offsetLeft + targetElem.offsetLeft;
}
else {
  containerOffset = panelsSection.parentElement.offsetTop + targetElem.offsetLeft - 10;
}

 

or use a ternary operator for that

 

const containerOffset = e.target.getAttribute("href").slice(9) === 'inner' ? 
      panelsSection.parentElement.offsetTop + targetElem.parentElement.offsetLeft + targetElem.offsetLeft : 
      panelsSection.parentElement.offsetTop + targetElem.offsetLeft - 10;

 

See the Pen 43cb579a3068d446ccd0acab72fbaba9 by akapowl (@akapowl) on CodePen

  • Like 2
Link to comment
Share on other sites

  • 10 months later...
On 4/9/2021 at 2:24 PM, akapowl said:

 

Welcome to the forum @tractaNZ

 

It pretty much works exactly the same as in the example you posted.

 

 

 

 

If this doesn't work for you, it would be best to create a minimal demo of your issues for us to have a look at.

 

Hope this helps, though.

 

so there's a catch when I increase the width of the thumbnail to 100vw; then the last three thumbnails doesn't show on scrolling only section 1 - 8 shows up,,, suppose if I have to make 100+ dynamic thumbnails, how will it adjust according to viewport...

Link to comment
Share on other sites

2 hours ago, Manan Tandon said:

so there's a catch when I increase the width of the thumbnail to 100vw; then the last three thumbnails doesn't show on scrolling only section 1 - 8 shows up

 

If you also adjust the width of the .wrapper accordingly, that should not be the case.

 

2 hours ago, Manan Tandon said:

suppose if I have to make 100+ dynamic thumbnails, how will it adjust according to viewport...

 

I'm not sure what it is you are asking. Could you maybe try and rephrase that?

 

As always, a minimal demo will help a lot for being able to give any thorough feedback.

 

Also please keep in mind that this is more of a concept and no one-size-fits-all-code-solution.

 

  • Like 2
Link to comment
Share on other sites

  • 9 months later...

hi

On 13.12.2020 at 10:26 PM, akapowl said:

 

בְּסֵדֶר,

כמו תמיד, כדי שמשהו כזה יעבוד, זה לא פתרון אחד שמתאים לכולם , אז אתה כנראה לא יכול לסמוך על ההדגמה הבאה שתעבוד בכל תרחיש שאפשר להעלות על הדעת. אבל הייתי סקרן בעצמי איך משיג משהו כמו מה שתיארת עובד והגעתי לרעיון הקטן הבא הזה.

 

זה עובד כמו שצריך (גם לאחר שינויי גודל), אבל אם תרצה לעשות דברים אחרת, תצטרך להחיל את השינויים בעצמך ולמצוא דרך להפעיל אותו בתרחיש שלך, אם ההדגמה שלי לא תעבוד בשבילך. זה רק למטרות הדגמה של איך אפשר להשיג את מה שהתכוונת.

 

לדוגמה, הוספתי שוליים כדי להרחיב את האלמנטים - והוספתי מעטפת סביב האלמנטים, שההדגמה שלי משמשת כאלמנט הטריגר עבור כל אחד מה-.thumbnail-ScrollTriggers. לעטיפה יש רוחב מוגדר (ששווה לרוחב של כל האלמנטים האלה בתוספת השוליים שלהם) - שבהחלט תצטרך להתאים לתרחיש שלך. זה אולי נראה פרוע, אבל זה באמת הגיוני. כמו כן, שים לב שיצאתי משימוש ב-display: flex ליישור ה-.thumbnails, כי זה המשיך להתעסק ברוחב של אותם אלמנטים, אז במקום זאת הלכתי להשתמש ב-display: inline-block ו-float שנשאר על ה-.thumbnails עצמם. . ישנם לא מעט שינויים אחרים ב-CSS, אבל זה יהיה יותר מדי להתייחס לכל אחד מהם כעת.

 

עבור ScrollTriggers עצמם:

אני משתמש בטריגר אחד להצמדת ה-.container - זה מה שהופך את כל העניין לגלילה. מכיוון שהיה לי אותו שם כבר, בלי לעשות שום דבר אחר, חשבתי שזה יהיה רעיון טוב למנף אותו גם להנפשה של סרגל הגלילה/המחוון המזויף שהערת עליו בהדגמה שלך.

 

הוספתי ScrollTriggers בודדים נוספים עבור כל אחת מהתמונות הממוזערות. 

אלה ללא הצמדה מזויפת בעצם מתנהגים אותו דבר, כפי שהתנהגת בהתחלה עבור כל המיכל שלך - אבל כאן זה קורה עבור כל חלק בנפרד. עבור אלה עם הצמדה מזויפת, הוספתי פונקציה נוספת, שמחשבת את הרוחב הכולל שלהם לזוז (המשמש לתרגום x שלהם, וסוף ה-ScrollTrigger) שלוקחת בחשבון את כל התמונות הממוזערות הקודמות עם הרוחב והשוליים שלהן.

 

זה אולי לא מושלם, אבל זה עובד בצורה הגונה.

 

וכפי שאתה רואה, זה לא הדבר הכי טריוויאלי שאפשר להבין - אלא אם כן אני מסבך יתר על המידה, מה שאולי כן.

 

עם זאת, זה לא לוקח בחשבון שבשלב מסוים, אולי תרצה 'לבטל' שוב תמונה ממוזערת, אבל זה יכול להיות מחושב גם עבור כל רכיב.

 

כמו כן, מה שאתה עשוי להבחין בהדגמה זו:

בהתאם למהירות הגלילה, יהיה 'קיזוז' גדול יותר לזמן ההצמדה המזויפת. אני חושב שזה רק קשור לאופן הפעולה של השפשוף - לא תראה אופסט כזה כשהקרצוף מוגדר כ-true במקום ערך אחר. אז אם אתה רוצה להיפטר מהקיזוז הזה, תצטרך להשתמש ב-scrub:true ואם אתה עדיין רוצה שכל העניין יהיה 'חלק', אז תצטרך גם להשתמש בספריית גלילה חלקה נוסף על כך.

 

עם כל מה שנאמר, הנה ההדגמה שדיברתי עליה כל הזמן

 

 

 

 

 

אני דווקא די אוהב את הרעיון, הוא מאפשר גם כמה אפקטי ערימה מסודרים.

 

 

 

 

 

בכל מקרה, אני יודע, ההגדרה שונה בהרבה ממה שפרסמת למעלה, ואולי זה קצת מסובך לעטוף את הראש סביב כל זה, אבל אני מקווה שזה עדיין עוזר לפחות להעביר רעיון, איך להגיע למה בדיוק שאתה צריך.

 

לחיים,

פול

 

Hey,
I am trying to add animations to the quoted code sample
But can't associate with the timeline to add a start and end to the animation
I would appreciate your help on how to add the timeline

Link to comment
Share on other sites

Hi,

 

This can be a tricky thing to do in the setup you currently have. You'd have to check the element where the child animation should happen and delay all the following sections until that particular animation is completed. In this thread that was discussed with quite some detail:

 

Honestly I think is better in this case to use the Container Animation feature for this:

https://greensock.com/3-8#containerAnimation

 

Hopefully that is enough to get you started. Let us know if you have more questions.

 

Happy Tweening!

  • Like 2
Link to comment
Share on other sites

1 hour ago, Rodrigo said:

Honestly I think is better in this case to use the Container Animation feature for this:

https://greensock.com/3-8#containerAnimation

Hi,

Thank you for your help
I'm quite new and working hard on a really complex website, this is a small question from a whole website full of animations (maybe after I'm done I'll share it with you :))
I tried using the Container Animation
But I wasn't able to create a good timeline to which I could attach the animation with a start and an end
If it's not difficult for you, it would really help me if you could demonstrate to me, I would really appreciate it from the bottom of my heart.

 

Link to comment
Share on other sites

היי


הצלחתי לשייך את האנימציה ל-  containerAnimation וזה עבד מצוין
אבל אחרי שהגדרתי את הכיוון מימין לשמאל
אז משהו משתבש
בפעם הראשונה לאחר הטעינה האנימציה מתבצעת מיד כשהיא מגיעה לקונטיינר ולא כשהיא מגיעה לטריגר. לאחר הפעם הראשונה זה עובד כמו שצריך
מה יכולה להיות הסיבה לכך?

See the Pen dyKaKeJ by chaniy (@chaniy) on CodePen

Link to comment
Share on other sites

Hi,

 

Help with what specifically? Sorry but I can't read the language you posted in (Hebrew I believe).

 

As I mentioned before there is an entire thread that deals with nesting animations in a horizontal setup.

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

 

I think it could be far better if you just remove ScrollTrigger all together and just get the animation working, once you get that out of the way, you can plug ScrollTrigger back in in order to get everything working in the way you intend.

 

Sorry I can't be of more assistance but with what you have provided there isn't much we can do, on top of that we can't give every user a fully working component or site, since we don't have the time resources to do so. We can guide you through GSAP-related questions/issues in order to get that part of your project going.

 

Happy Tweening!

  • Like 1
Link to comment
Share on other sites

  • 1 year later...

@akapowl

Thanks for your solution from  December 13, 2020. I'm trying to do something similar where my application scrolls down to a section with the horizontal scroll. For my react / next.js application, and much like your solution, I am trying to have all my sections scroll horizontally to the left, pin, and overlap each other. Once I scroll through the sections then the container's horizontal scroll should disengage and move vertically down to the rest of the web page. My problem is that when I engage in the first scroll, it somehow makes the container disappear and does not allow for the subsequent thumbnails to stick. What's an even stranger effect, the horizontal scroll does appear but only in reverse after I scroll to the bottom of the page first. Since I am using next.js I am utilizing useRefs instead of query selectors. Could this be a reason my app is experiencing this odd behavior?

Here's my sandbox attempt:
https://codesandbox.io/p/sandbox/horizontal-scroll-with-left-sticking-panels-6yg39f?file=%2Fsrc%2FStickyScroll.jsx%3A7%2C29

 
Link to comment
Share on other sites

Hi @nyldev,

 

You already created a thread here:

 

There is no need to create or post in multiple threads in order to get an answer, we try to answer every to every post in less than 24 hours. I already answered in that thread so let's keep our focus in that one so it makes it easier for everyone to track this.

 

Happy Tweening!

  • Thanks 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.
×
×
  • Create New...