Jump to content
GreenSock

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

many scrollTrigger in one page not working properly

Recommended Posts

hello everyone, sorry for my poor english first.

I want  my project look like google art exhibition, so I use Vue and GSAP to make this demo

it work perfectly on pc, but something wired occured on mobile device (try codepen debug mode on your phone)

video of wired occured on mobile

 

 

the core code in codepen demo is initAnimation() 

    initAnimation(){
      const vm = this;
      const blockId  = vm.blockData.blockId;
      const tl = gsap.timeline({defaults:{ duration: 1}});
      const $container = vm.$refs.container;
      const $img = vm.$refs.image;
      const posData = [];

      vm.blockData.itemList.forEach(function(item){
        
        let x = item.x;
        let y = item.y; 

        posData.push({ 
          x:`${x}%`,
          y:`${y}%`,
          scale: item.scale,
        });
  
        tl.add([
          tl.to(`#immersive${blockId}-${item.itemId}`, { opacity: 1, y: "-10%" }),
          tl.to(`#immersive${blockId}-${item.itemId}`, { opacity: 1, y: "-10%", duration: 5}),
          tl.to(`#immersive${blockId}-${item.itemId}`, { opacity: 0, y: "10%" }),        
        ])
  
      })
      
      // set text animation
      ScrollTrigger.create({
        animation: tl,
        trigger: $container,
        start: "top top",
        end: `+=${vm.blockData.itemList.length * 1500}`,
        scrub: true,
        pin: true,
        anticipatePin: 1,
        // markers: true,
      })
      
      // set image animation
      // delay to get real container height above
      setTimeout(function(){
        const realHeight = $container.parentNode.offsetHeight - $container.offsetHeight;

        posData.forEach((pos,index)=>{
          if(index === 0) return;          
          const thisFromTo = gsap.fromTo($img,posData[index-1],{...pos,duration: 1});

          ScrollTrigger.create({
            animation: thisFromTo,
            trigger: $container.parentNode,
            toggleActions: 'play none none reverse',
            // set trigger point (according container height)
            start: `${(index / posData.length)* realHeight}px`,
            end: '+=20',
            anticipatePin: 1,
            // markers: true
          })
        })

        gsap.set($img,posData[0]);
      },500)
    }

data structure of one block container look like this, here is all data

        {
            "blockId": 1044,
            "itemList": [
                {
                    "itemId": 3149,
                    "url": "https://images.unsplash.com/photo-1603486001734-7d92cedd1d33?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ",
                    "description": "lorem lorem lorem",
                    "x": -25,
                    "y": 3,
                    "scale": 1
                },
                {
                    "itemId": 5568,
                    "url": "https://images.unsplash.com/photo-1603486001734-7d92cedd1d33?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ",
                    "description": "lorem2 lorem2 lorem2",
                    "x": 6,
                    "y": -12,
                    "scale": 1
                }                
            ]
        },

 

I notice this situation seems only happened while having many scrollTrigger on page (or not)

and also occured when window.resize event fired (mobile address bar show/hide while scrolling)

Any suggestion to fix this, or better way to achieve this effect ? (google art exhibition)

 

Thanks you for reading here

 

See the Pen KKMaVdN by handred800 (@handred800) on CodePen

Link to post
Share on other sites

Hey @handred0008

 

I think this is related to using start- and/or end-points for your ScrollTriggers, that are dependend on the height of your container elements for example.

Since your .immersive-container's height is set to 100vh via CSS, it will change on resize (and thus also when the mobile browser's nav-bars are being hidden/shown).

 

You'd have to consider those changes in height of your container and thus also the position of later containers on the whole page, when setting up your ScrolTriggers. The way to do that, is to use function-based start and end-points, so your ScrollTriggers can get that new height of your elements after a resize and accomodate for the changes.

 

Just as an example to post here, I changed your:

 


ScrollTrigger.create({
  animation: thisFromTo,
  trigger: $container.parentNode,
  toggleActions: 'play none none reverse',
  // set trigger point (according container height)
  start: `${(index / posData.length)* realHeight}px`,
  end: '+=20',
  anticipatePin: 1,
  // markers: true
})

 

to this:

 

ScrollTrigger.create({
  animation: thisFromTo,
  trigger: $container.parentNode,
  toggleActions: 'play none none reverse',
  // set trigger point (according container height)
  start: () => `${(index / posData.length)* $container.parentNode.offsetHeight - $container.offsetHeight}px`,
  end: () => '+=20',
  invalidateOnRefresh: true,            
  // markers: true
})

 

 

(and your other ScrollTriggers to function based start and end-points, too)

 

Additionaly to what I wrote above, I added 

 

invalidateOnRefresh: true

 

to your ScrollTriggers (and from the one you can see as an example, I removed the anticipatepin, because you don't pin anything with that trigger).

 

 

...and it seems to handle the resize better now. At least, I don't see that white space appear anymore, when resizing.

 

 

Working with viewport-height based values tends to get tricky in regards to mobile, though.

I can not guarantee, that this will absolutely solve your problem on mobile, because I didn't test it.

 

 

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

 

 

But you can go ahead and test it for yourself - I hope it helps.

 

Cheers,

Paul

 

 

  • Like 4
Link to post
Share on other sites

@akapowl thanks for your reply

I test the demo, but nothing seems to have changed

And you mention about  viewport-height, so I update my demo using fixed height value

:style="{height: `${screen.height}px`}"

// get window.innerHeight once
screen: {
  width: window.innerWidth,
  height: window.innerHeight,
}  

but problems still occured..

 

btw, I notice that reloading page can reduce the chance of bug happen  (but still can be triggered via resize event)

just wonder that is this GSAP's bug, or I using plugin in wrong way ?

thanks again anyway ❤️

 

Link to post
Share on other sites

I'm not a Vue guy and there's too much going on in your demo for me to dig through it all (and it looks like it's leveraging axios too) but my best guess (in addition to what Paul already said) is that you've got timing issues too. In order for ScrollTrigger to effectively map positions correctly, it needs to walk through the pinned sections one-by-one, top-to-bottom because their spacing affects one another (the ones above push the ones below down). It looks like you've got a setTimeout() that's creating several other ScrollTriggers 500ms after the first batch. I'd strongly recommend avoiding that. Either create all your ScrollTriggers initially and in the order they'd appear in the viewport or set a refreshPriority to tell ScrollTrigger what order they should be refreshed in. 

 

If you still need some help, please provide a reduced test case with the absolute bare minimum, like just 2 sections and no Vue/axios entanglements and we'd be happy to take a peek. 

 

Oh, and you can just call ScrollTrigger.refresh() instead of the longer ScrollTrigger.getAll().forEach((item) => {  item.refresh(true); }); that you're doing. 

  • Like 2
  • Thanks 1
Link to post
Share on other sites

@GreenSock thanks for reply 

 

I using setTimeout because I can not get proper height of DOM right after scrollTrigger created

here is the core code ( initAnimation ) doing:

step 1: create text scrollTrigger (pinned)

oeXstxb.jpg

step 2: create image animation scrollTrigger

oOtNIzL.jpg
in above example there two item in itemList, so start point will be (index / 2) * containerHeight  pixel (from top of container)

but I get 0 (container height) right after step 1, you can see console output in my demo

 

phew. maybe there are better solution to get this effect (google art exhibition)

-----

 

20 hours ago, GreenSock said:

Either create all your ScrollTriggers initially and in the order they'd appear in the viewport or set a refreshPriority to tell ScrollTrigger what order they should be refreshed in. 

could you provide any example ? 

 

About the Vue and axios doing is just create html template easily

Anyway I'll make another demo without these tools later

 

thanks for your support so much❤️

 

Link to post
Share on other sites
45 minutes ago, handred0008 said:

could you provide any example ? 

An example of setting a refreshPriority? 

ScrollTrigger.create({
  refreshPriority: 1,
  ...
});

The higher the priority, the earlier it'll run in the refresh() sequence. The default is 0. You can use negative numbers too. It's all in the docs. 

 

47 minutes ago, handred0008 said:

About the Vue and axios doing is just create html template easily

Anyway I'll make another demo without these tools later

Yeah, the simpler the better. There are just too many things going on right now in your demo to effectively troubleshoot. Once you boil it down to something simpler (and without Vue/axios), we'd be happy to take a peek. 

 

Good luck!

  • Like 2
  • Thanks 1
Link to post
Share on other sites

@GreenSock thanks guys !

 

I follow your suggestion, and updated the demo :

On 10/27/2020 at 3:00 PM, GreenSock said:

Either create all your ScrollTriggers initially and in the order they'd appear in the viewport or set a refreshPriority to tell ScrollTrigger what order they should be refreshed in. 

 

I create scrollTrigger after all html/image render finish, and it worked porperly

but I still use setTimeout because I can not get proper height right after scrollTrigger created

you can read my last post above that explain my code doing.

 

thanks for support ❤️

 

Link to post
Share on other sites

I didn't really understand your question. If you still need help, please create the most minimal case possible to demonstrate the issue and clearly describe the GSAP-specific question you have and we'd be glad to do our best to help. And in this case, what does "proper height" mean exactly? What are you expecting, and how does that differ from what you're getting? 

  • Like 1
Link to post
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.

×