Jump to content
Search Community

Need help trying to recreate an scroll animation using ScrollTrigger

pattwala test
Moderator Tag

Go to solution Solved by elegantseagulls,

Recommended Posts

Hi Greensock community,

 

I don't use GSAP nearly as much as I'd like to and each time I start a project using it I feel like I'm having to relearn it! So, having said that I'm trying to recreate an effect very similar to the one found on this website: http://fillet.com.br/

 

In the example noted above, it's got a 3 column layout where the columns appear to scroll in alternating directions. And, the contents of each container appear to remain pinned while the container itself appears to scroll naturally.

 

Really appreciate any help you can provide to get me on the right path as I'm super stumped!

 

Pramesh

  • Like 1
Link to comment
Share on other sites

  • Solution

The way I'd approach this would be to set a full-height container that I'd pin for the duration of your animations then create a single gsap.timetime for all the columns and content inside that container and use ScrollTrigger's scrub feature to move through that animation timeline while the container is pinned.

 

A good way to approach / set this up would be to first make your timeline play through nicely without any scrolling, then append that to the scroll/scrub/pin and adjust the duration (distance) of the pin to match the feel of your desired animation at a natural scroll speed.

  • Like 4
Link to comment
Share on other sites

  • 4 weeks later...

Hi again,

 

Firstly, just want to thank @elegantseagulls and @Trapti for pointing me in the right direction to get me started. Your help was greatly appreciated. 

 

My site is 99% done, but I've got a glitch happening is iOS Safari that I'm having trouble solving. It happens at the very end of the timeline, so you would need to scroll to the end of the page to see it happen -- the issue: the timeline animation jumps at the end, probably due to iOS Safari's rubber-band effect, and the screen momentarily goes blank. 

 

Here's a video of the issue that's happening here: https://www.dropbox.com/s/02wlgryopxzyxcx/RPReplay_Final1622519647.mp4?dl=0. You will need an iPad to see it happen locally . I've disabled the timeline & scroll trigger on smaller devices (ie. phones). Unfortunately, I'm unable to "inspect" for the issue because I don't have a USB-C to USB-C cable to connect the iPad to my Mac.

 

You can visit the site here: https://homepage4change.github.io/ (in Safari iOS on an iPad)

 

Here's the timeline registration block:

//$ and $$ -- Query selector shorthands
const $ = document.querySelector.bind(document);
const $$ = document.querySelectorAll.bind(document);

const app = $("#app");  // #app is the main container for the timeline
const slates = $$('.slate'); // first and last <section> elements
const cards = $$('.card');  // all the <section> dom elements between the slates

tl = gsap.timeline({
  // Attach it to the scroll
  scrollTrigger: {
    trigger: app,
    pin: true, 
    start: "top top", 
    end: () => `+=${app.offsetHeight * (cards.length/2 + slates.length/2)}`,
    scrub: 0.3,
    invalidateOnRefresh: true,
    onRefresh: self => tl.progress(self.progress)
  }
});

and here's the timeline setup:

// Animation duration
const d = 1;

//Move the first two cards into the center position
tl.fromTo('.card:nth-child(2)', {y:"100%"},{y:0,duration: d, ease: 'linear'});
tl.fromTo('.card:nth-child(2) .container',	{y:"-100%"},{y:0,duration: d, ease: 'linear'},"-="+d);
tl.fromTo('.card:nth-child(2) .nav-element',{y:-1*innerHeight},{y:0,duration: d, ease: 'linear'},"-="+d);

tl.fromTo('.card:nth-child(3)', {y:"-100%"}, {y:0,duration: d, ease: 'linear'},"-="+d);
tl.fromTo('.card:nth-child(3) .container', {y:"100%"}, {y:0,duration: d, ease: 'linear'},	"-="+d);
tl.fromTo('.card:nth-child(3) .nav-element',{y:innerHeight},{y:0,duration: d, ease: 'linear'},"-="+d);

//Hide the hero
tl.to('#hero', {y:"100%",duration: 0, ease: 'linear'});

//Animate all the cards
for(let i = 1; i < cards.length-2; i+=2) {
  //target                       //from  //to    //duration //delay
  tl.fromTo('.card:nth-child('+(i+1)+')', {y:0}, {y:"-100%",duration: d, ease: 'linear'});
  tl.fromTo('.card:nth-child('+(i+1)+') .container', {y:0}, {y:"100%",duration: d, ease: 'linear'},"-="+d);
  if($('.card:nth-child('+(i+1)+') .nav-element')) {
    tl.fromTo('.card:nth-child('+(i+1)+') .nav-element', {y:0},{y:innerHeight,duration: d, ease: 'linear'},"-="+d);
  }

  tl.fromTo('.card:nth-child('+(i+3)+')', {y:"100%"}, {y:0, duration: d, ease: 'linear'}, "-="+d);
  tl.fromTo('.card:nth-child('+(i+3)+') .container', {y:"-100%"}, {y:0, duration: d, ease: 'linear'},"-="+d);
  if($('.card:nth-child('+(i+3)+') .nav-element')) {
    tl.fromTo('.card:nth-child('+(i+3)+') .nav-element', {y:-1*innerHeight},{y:0, duration: d, ease: 'linear'},"-="+d);
  }

  tl.fromTo('.card:nth-child('+(i+2)+')', {y:0}, {y:"100%",duration: d, ease: 'linear'},"-="+d);
  tl.fromTo('.card:nth-child('+(i+2)+') .container', {y:0}, {y:"-100%",duration: d, ease: 'linear'},	"-="+d);
  if($('.card:nth-child('+(i+2)+') .nav-element')) {
    tl.fromTo('.card:nth-child('+(i+2)+') .nav-element', {y:0},{y:-1*innerHeight,duration: d, ease: 'linear'},"-="+d);
  }

  tl.fromTo('.card:nth-child('+(i+4)+')', {y:"-100%"}, {y:0, duration: d, ease: 'linear'},"-="+d);
  tl.fromTo('.card:nth-child('+(i+4)+') .container', {y:"100%"}, {y:0, duration: d, ease: 'linear'},"-="+d);
  if($('.card:nth-child('+(i+4)+') .nav-element')) {
    tl.fromTo('.card:nth-child('+(i+4)+') .nav-element', {y:innerHeight}, {y:0, duration: d, ease: 'linear'},"-="+d);
  }
}

//Move the last two cards off stage to reveal the final section
tl.fromTo('.card:nth-child('+(cards.length)+')', {y:0},{y:"-100%",duration: d, ease: 'linear'});
tl.fromTo('.card:nth-child('+(cards.length)+') .container', {y:0},{ y:"100%", duration: d, ease: 'linear'},"-="+d);
if($('.card:nth-child('+(cards.length)+') .nav-element')) {
  tl.fromTo('.card:nth-child('+(cards.length)+') .nav-element', {y:0}, {y:innerHeight,duration: d, ease: 'linear'},"-="+d);
}

tl.fromTo('.card:nth-child('+(cards.length+1)+')', {y:0}, {y:"100%",duration: d, ease: 'linear'},"-="+d);
tl.fromTo('.card:nth-child('+(cards.length+1)+') .container', {y:0}, {y:"-100%",duration: d, ease: 'linear'}, "-="+d);
if($('.card:nth-child('+(cards.length+1)+') .nav-element')) {
  tl.fromTo('.card:nth-child('+(cards.length+1)+') .nav-element', {y:0}, {y:-1*innerHeight, duration: d, ease: 'linear'},"-="+d);
}

tl.totalProgress(progress || 0);


Thanks again for any help you can provide!

 

Pramesh

Link to comment
Share on other sites

Hi Pramesh. Nice work on the site. Looks cool.

 

Unfortunately we can't really provide free troubleshooting for a live site like that. If you want some assistance, please provide a minimal demo and strip out everything that's not absolutely essential. So, for example, if the problem is only happening on the final section, strip out all the others. That's usually a really good habit to get into for your own troubleshooting too. A lot of times the problem becomes much clearer when you boil it down to only the absolutely essential pieces to reproduce it. 

 

Small tip: always use yPercent: -100 instead of y: "-100%" in order to keep the values properly segregated. Remember, you can combine y and yPercent for some really useful effects. 

 

Happy tweening!

  • Like 4
Link to comment
Share on other sites

Hi @pattwala,

 

I was able to reproduce on desktop Safari too. It seems to be stemming from your CSS file:

#app {
	transition: filter 0.6s ease-in-out;
	height: calc(var(--vh, 1vh) * 100) !important;
	max-height: calc(var(--vh, 1vh) * 100) !important;
	transform: translate(0px, 0px) !important; /* removing this line fixes it */
}

Commenting out the transform here seems to fix the issue.

  • Like 2
Link to comment
Share on other sites

Hi @elegantseagulls -- that seems to do the trick! I'd thrown that transform in there in an attempt to solve this issue earlier on when I was troubleshooting and must have forgotten to remove it. Thank you for taking the time to help debug my code!

 

@GreenSock -- Thanks for your note as well. I'll keep it in mind for the next time I jump here for support, to create a minimal demo. As for changing to yPercent: -100 from y: "-100%", that really messed things up for me. I suspect I would need to change a few other things in order to make that work as intended.

  • Like 1
Link to comment
Share on other sites

4 hours ago, pattwala said:

@GreenSock -- Thanks for your note as well. I'll keep it in mind for the next time I jump here for support, to create a minimal demo. As for changing to yPercent: -100 from y: "-100%", that really messed things up for me. I suspect I would need to change a few other things in order to make that work as intended.

I'd have to see the issue in context, but my guess is that you made one of the most common mistakes by not setting all your transforms via GSAP. You probably just need to set the "y" and "yPercent" initially to what it should be because the browser always reports computed values in px so GSAP can't possibly know that you intended percent. Again, that's why we always encourage people to set things via GSAP directly. It's more accurate and boosts performance. 

  • Like 1
Link to comment
Share on other sites

@GreenSock Appreciate the follow up. I slowed down a bit to read the post you shared which was a helpful reference. Earlier, it was "messed up" because of of CSS properties that needed to be removed. I did that and updated it to use yPercent and it's working perfectly. Thank you again!

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