Jump to content
GreenSock

romain.gr

Advices for using Locomotive Scroll and Gsap ScrollTrigger pin horizontal scroll

Recommended Posts

Hi,

 

I'm currently testing Locomotive Scroll and Gsap ScrollTrigger, I've read somewhere on the forum that horizontal scroll pin using Locomotive scroll is not that possible (is that correrct?). In fact, each sections are translated, so even though position fixed is set it's still translated, furthermore I think the width of each section is calculated (by Locomotive Scroll) before the "pushing" padding to the section is set. I played with all the pin options (pinType, pinSpacing, pinnedContainer, pinReparent) , without success, I understand in a nutshell what those stuff fixes in general but I haven't been able to make that work properly. So I found a workaround but I was hoping for a "cleaner" way to achieve what I've done.

 

The workaround is to create a wider section (200vw), inside of it a container (100vw), absolute positioned, and translate that container on progress, that work pretty good but I feel that is a hack and I was wondering if I could do it differently. I could use a timeline that I scrub play, but I don't think it's a better solution.

 

The section I'm talking about are the ".section--curtain" one, you need to scroll at the end, that's the 2 fixed sections with curtains opening vertically and horizontally.

 

1.  

style="transform: translate(56.3%, 0%) scale(1.1877, 1.18767);

translate instead of translate3d? Why? Shouldn't be smoother if translate3d was used?

 

2. The image is slightly zooming, again on progress but it's not very smooth. 

 

on line 160 

 

$('.section--curtain--horizontal').each(function(){
	var thisCurtainTop = $(this).find('.curtain--top');
	var thisCurtainBottom = $(this).find('.curtain--bottom');
	var curtainPin = $(this).find('.curtain-pin');
	var thisMedia = $(this).find('.curtain-media');
	
	gsap.to(thisCurtainTop, {
		yPercent: -100,
		ease: 'none',
		scrollTrigger: {
			trigger: $(this),
			scroller: '.scroll-wrapper',
      horizontal: true,
			scrub: true,
			//pin: true,
			//pinType: 'transform',
			//pinSpacing: 'margin',
			//pinnedContainer: curtainPin,
			start: 'left left',
			end: () => {return '+=' + window.innerWidth + 'px'},
			//markers: true,
			invalidateOnRefresh: true,
			onUpdate: self => {
				var progress = self.progress.toFixed(3) * 100;
    		//console.log("progress:", self.progress.toFixed(3) * 100);
				gsap.set(thisMedia, {xPercent: progress, zPercent: 0});
				gsap.to(thisMedia, 1, {scale: 1 + progress / 300})
  		}
			
		}
	});
	
		gsap.to(thisCurtainBottom, {
			yPercent: 100,
			ease: 'none',
			scrollTrigger: {
				trigger: $(this),
				scroller: '.scroll-wrapper',
				horizontal: true,
				scrub: true,
				//pin: true,
				//pinType: 'transform',
				//pinSpacing: 'margin',
				//pinnedContainer: curtainPin,
				start: 'left left',
				end: () => {return '+=' + window.innerWidth + 'px'},
				//markers: true,
				invalidateOnRefresh: true
			}
	});
});

$('.section--curtain--vertical').each(function(){
	var thisCurtainLeft = $(this).find('.curtain--left');
	var thisCurtainRight = $(this).find('.curtain--right');
	var curtainPin = $(this).find('.curtain-pin');
	var curtainS = $(this).find('.curtains');
	var thisMedia = $(this).find('.curtain-media');
	var thisVid = $(this).find('video')[0];
	
	gsap.to(thisCurtainLeft, {
		xPercent: -100,
		ease: 'none',
		scrollTrigger: {
			trigger: $(this),
			scroller: '.scroll-wrapper',
			horizontal: true,
			scrub: true,
			//pin: true,
			//pinType: 'transform',
			//pinSpacing: 'margin',
			//pinnedContainer: curtainPin,
			start: 'left left',
			end: () => {return '+=' + window.innerWidth + 'px'},
			//markers: true,
			invalidateOnRefresh: true,
			onUpdate: self => {
				var progress = self.progress.toFixed(3) * 100;
				//console.log("progress:", self.progress.toFixed(3) * 100);
				gsap.set(thisMedia, {xPercent: progress, zPercent: 0});
				gsap.set(curtainS, {xPercent: progress, zPercent: 0});
				gsap.to(thisMedia, 1, {scale: 1 + progress / 300});
			},
			onEnter: () => { 
				thisVid.play();
			},
			onEnterBack: () => {
				thisVid.play();
			},
			onLeave: () => {
				thisVid.pause();
			},
			onLeaveBack: () => {
				thisVid.pause();
			},
		}
	});
	
		gsap.to(thisCurtainRight, {
		xPercent: 100,
		ease: 'none',
		scrollTrigger: {
			trigger: $(this),
			scroller: '.scroll-wrapper',
      horizontal: true,
			scrub: true,
			//pin: true,
			//pinType: 'transform',
			//pinSpacing: 'margin',
			//pinnedContainer: curtainPin,
			start: 'left left',
			end: () => {return '+=' + window.innerWidth + 'px'},
			//markers: true,
			invalidateOnRefresh: true,
		}
	});
});

 

 

 

 

1.gif.84db2de08b0bbdd50a26fb1b8d387b24.gif1440499794_Capturedecran2021-10-26a17_19.gif.a36f8945e0779d11fc0f0470bd9507b2.gif

 

I'm happy if there is some examples, somewhere, hope everything is clear.

 

Thank you

 

 

 

See the Pen yLoJWpE by romaingranai (@romaingranai) on CodePen

Link to comment
Share on other sites

Hi @romain.gr. Cool animation! 👏

 

A few comments...

  1. LocomotiveScroll is not a GreenSock product, so we can't really offer free support services for it here. 
  2. You'll have a MUCH greater chance of getting a solid response if you provide a minimal demo that ONLY shows the one isolated part that you're struggling with, and focus on a single question in each thread you create. It's a lot to ask the community hear to read through 500+ lines of JS/CSS/HTML and try to comprehend everything that's going on. 
  3. GSAP does use translate3d() during the animation and then automatically switches back to translate() (if possible) when the animation is done in order to maximize performance during the animation and then maximize rendering sharpness when not animating. 
  4. There's no such thing as zPercent
  5. This looks expensive to me - is there a reason why you didn't use a regular tween instead of re-creating a new tween every single time the ScrollTrigger updates?: 
    onUpdate: self => {
      var progress = self.progress.toFixed(3) * 100; // why round? why use a string?
      gsap.set(thisMedia, {xPercent: progress, zPercent: 0}); // no such thing as zPercent. This would be much more efficient if you used a regular tween with a ScrollTrigger instead of doing a set() over and over and over again every onUpdate. 
      gsap.to(thisMedia, 1, {scale: 1 + progress / 300}); // why not use regular tween with a numeric scrub?
    }

     

  6. Is there some reason you're using LocomotiveScroll instead of the ScrollTrigger-based

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

    helper function that's in the docs
  7. Why such heavy usage of jQuery? I mean it's fine, but you could do all that without jQuery pretty easily. 

If you still need some help, I'd definitely recommend reworking your demo to isolate things further. And again, we can't really offer free support for 3rd party tools like LocomotiveScroll here (please see the forum guidelines).

 

Happy tweening/scrolling!

  • Like 1
Link to comment
Share on other sites

Hi Jack,

 

Thanks for your quick answer.

 

1. I do know Locomotive Scroll is not a GSAP product, however Locomotive Scroll and Gsap are often used together, furthermore the question was destined to those who have use them together, those who had a similar problem/question, those who would be able to help me. But I promise I will ask the same question on the Locomotive Scroll Github, hope they won't tell me "Gsap Scroll Trigger is not a Locomotive Scroll product, see with Gsap" ;).

 

2. Here it is! 

See the Pen ZEJKqOG by romaingranai (@romaingranai) on CodePen

 

3. Ok, thanks,

 

4. ;) thanks

 

5. That was my main question, and you answer me by asking me the same question, So I'm reformulating: 

          a. Does anyone had similar issue using Gsap ScrollTrigger and Locomotive Scroll?

                    I. The issue is : struggling with Pinning stuff on smooth horizontal scroll (only a horizontal scroll, not vertical then a section that scroll horizontal).

                    II. I found a workaround but, is there a better way to achieve this? Is there a "Gsap friendly" way to achieve this? (partly answered, thank you)

                    |||. A demo?

 

6.  I'm using Locomotive Scroll because :

          a. It seems to be a common practice, I've seen multiple examples on codepen and a lot of questions on this forum about using Gsap ScrollTrigger AND Locomotive Scroll, so I conclude that it wasn't a bad idea to do so.

          b. I already knew more or less how to use Locomotive Scroll, and a little bit how to use Gsap, so why not use both?!

          c. On the page you sent me docs there is an example using Locomotive Scroll, again my conclusion is : Gsap doc is explaining how to use Locmotive Scroll and Gsap, it must be a good practice to do so, why not give it a try.

          d. It's super easy to do parallax with Loco scroll (just adding data attribute to html el), perfect for prototyping, even though you can easily achieve the same with gsap, it's easier and faster with Loco (from my point of view). 

          e. I had no idea, until now that Gsap had a "built in" smooth scroll (I'm sure like a lot of people), that functionality is a bit hidden in the doc, at least if you don't know about it, it's hard to find out it exists. I'm pretty sure if they were "promoting" that functionality, you would have way less questions related to Gsap using Locomotive Scroll on this forum. To those who are reading this : You don't need Locomotive Scroll to do smooth scroll, GSAP has is own smooth scroll functionality, doc about it here

 

7. 👍

 

If you are not able to give me support on Gsap and Locomotive Scroll, I understand, but maybe someone else can (see point 1), it's a forum after all, anyone interested can participate. If it's totally forbidden to ask question about GSAP + another library, I'll stop to ask, but I need a confirmation.

 

Furthermore if anybody has a demo (a horizontal demo), of the gsap smoothScroll + (+) pinning stuff, I'll be grateful.

 

Thank you

 

 

 

 

 

 

Link to comment
Share on other sites

Hello @romain.gr

 

From my experience, ScrollTrigger's pinning works just fine with locomotive-scroll, even in a horizontal-scroll scenario.

 

See the Pen 87ad10833ca73c5a1ea59190fae48e32 by akapowl (@akapowl) on CodePen

 

 

However, ScrollTrigger's pinning will not work with sections that make use of locomotive-scroll's data-scroll-section attribute (and it doesn't matter if you are scrolling vertically or horizontally), as when using that data-attribute, locomotive-scroll will work its translates for the smooth-scrolling on those sections and thus will inevitably tell those sections to keep on moving/translating, so there will be conflicting behaviour between locomotive-scroll and ScrollTrigger, that ScrollTrigger can not do much about.

 

 

  • Like 2
Link to comment
Share on other sites

Hi akapowl

 

Great, I think I got it, it's quite simple, instead of translating each sections using data-scroll-section attribute, you translate the whole content, and then you can pin it when you want. That's perfect, I actually thought that the only way to use Loco Scroll was to was adding those attributes to each sections, my bad. Thanks, for the quick explanation, makes total sens. I'm going to have a look at that rn.

 

Thanks

Link to comment
Share on other sites

As their docs state: "Splitting your page into sections may improve performance."

But using those is just an option - the basic functionality is moving the whole container.

 

In a scenario like yours, where the sections fill the whole window anyway and it won't make a visible difference, you could also workaround the problem by setting the section's width to accomodate for the pin-duration (what you already did by setting it to 200vw) and pin an inner container instead with pinType specifically set to "transform". Technically that will probably do about the same thing that you tried with the transforms, but ScrollTrigger will handle it for you.

 

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

 

  • Like 3
Link to comment
Share on other sites

Hi @akapowl

 

I've made some changes, following your advices and that works very nicely! Thank you. Except for one thing, it scrolls further the last slide/section. It seems the scroll distance is not correctly calculated. It drives me nut for hours and it's not the first time I have that issue with Loco scroll, and for info nothing is depending on images size (so no prob with image not loaded), as everything is size in css in vw,...! I literally copy/past and adapt your code adapted it with my content. It's definitely a Loco scroll issue so I'll ask there if nobody has an idea on what s going here.

 

Thank you!

 

See the Pen vYJmPqO by romaingranai (@romaingranai) on CodePen

 

  • Like 1
Link to comment
Share on other sites

I didn't mean to imply that it was "bad" to use LocomotiveScroll. Not at all - I'm not very familiar with it. I'm sure it's great. I'm just usually not a fan of scroll-jacking personally. It's also why we created a ScrollTrigger-based one that leverages the native scroll to make it as close to "real" as we could (and minimize device issues). 

 

Also, to clarify what I meant about using a regular tween instead of doing a new .set() over and over again in an onUpdate: 

// BAD
gsap.to(thisCurtainTop, {
	...
	scrollTrigger: {
		...
		onUpdate: self => {
			var progress = self.progress.toFixed(3) * 100;
			gsap.set(thisMedia, {xPercent: progress});
		}
	}
});


// GOOD
gsap.to(thisMedia, {
	xPercent: 100,
	scrollTrigger: {
		// same values (except no onUpdate of course)
	}
});

 

9 hours ago, romain.gr said:

but maybe someone else can (see point 1), it's a forum after all, anyone interested can participate.

Of course! That's what we love about these forums - participation from the community. I just like to manage expectations of our team, that's all. You'd be surprised how many people come to these forums asking us to solve their logic issues, code projects for them, support 3rd party tools, do performance audits, etc. :) We spend a crazy amount of time providing free support around here, so we've gotta help people understand what's reasonable to expect.

 

Thanks to @akapowl for jumping in with suggestions!

  • Like 3
Link to comment
Share on other sites

  • 2 weeks later...

Hi,

 

Just wanted to say that if anyone experiences wider scroll than the content using GSAP and Locomotive scroll, here is 2 reasons why it can happen :

 

1. An unclosed tag somewhere, couldn't believe I missed it!

And very strangely 

2. When you leave a markers: true in your scrollTrigger. So more you have markers to debug, more wide will be the "further-scroll". Just remove the markers: true.

 

 

  • Like 1
Link to comment
Share on other sites

  • 5 months later...

Hello I stumbled upon this thread while trying to use both locomotive scroll and gsap together and came across this exact problem. I am super new to both locomotive scroll and gsap and was wondering if what I am doing is correct. I ended up deleting data-scroll-section from all of the components in my entire project and the pinned component started to work. Would there be any issue with not using data-scroll-section? I don't have a codepen of my project but once I have time I will post again.

Link to comment
Share on other sites

11 minutes ago, scottlynotlie said:

Would there be any issue with not using data-scroll-section?

 

That feature will not work with ScrollTrigger, so it's fine. Also, we have our own smooth scrolling plugin for Club GreenSock members.

 

https://greensock.com/scrollsmoother/

 

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