Jump to content
Search Community

Scrollsmoother with lazysizes/lazyload images

Superloop test
Moderator Tag

Recommended Posts

I ran into the same issue with a tabbed component changing the content height. The only solution I found was to dispatch a resize event which ScrollTrigger refreshes values on pretty gracefully.

window.dispatchEvent(new Event("resize"));

 

This also works as images lazily load in, but there is some undesired jank as things recalculate while the scrolling is mid-tween

document.querySelectorAll("img[loading=lazy]").forEach((i) => {
  i.addEventListener("load", (e) => {
    window.dispatchEvent(new Event("resize"));
  });
});
  • Like 1
Link to comment
Share on other sites

 

12 hours ago, walpolea said:

Thanks! This works. I wrote this off because I had tried:

const sm = SccrollSmoother.create(...)                                
//... then later
sm.scrollTrigger.refresh()

Which did not work.

 

I made some tests but it doesn't work... I edit my codepen. You will see you can get "last" div. 

See the Pen OJzQgRQ by marctaule (@marctaule) on CodePen

 

If I use refresh in every image loaded, it seems that works but there are some performance problems.
 

document.addEventListener('lazyloaded', function(e){
	smoother.ScrollTrigger.refresh();
});

 

Link to comment
Share on other sites

I think it's less performance problems and more that the refresh stops the existing scroll tween, causing a stuttering effect. Given the nature of lazy-loaded images (which load as you scroll them near the viewport) I'm not sure there is much to be done, perhaps wait until the velocity is closer to 0 like this:

let needsToRefresh = false;

document.addEventListener('lazyloaded', function(e){
  needsToRefresh = true;
  refresh();
});

function refresh() {
  if( needsToRefresh && smoother.getVelocity() < 0.01 ) {
    ScrollTrigger.refresh();    
    needsToRefresh = false;
  } else if( needsToRefresh ) {
    requestAnimationFrame(refresh);
  }
}

Still not the best experience. Definitely the killer feature would be for gsap to somehow not stop the scrolling tween as ScrollTrigger refreshes.

Link to comment
Share on other sites

4 hours ago, Marc Taule said:

If I use refresh in every image loaded, it seems that works but there are some performance problems.

You had a typo in your code that was throwing an error. I'm not sure why you were trying to call .refresh() on the smoother's ScrollTrigger (before your images even loaded). 

 

I didn't realize you were using a different library and only loading the images on-demand. In that case, yes, you'd need to at least call .refresh() on the individual ScrollTrigger associated with that newly-loaded image.

 

Originally, I thought you were just starting the load of all the images after your page loaded (without the images), so this is what I was talking about: 

function onLoadImages(selector, callback) {
  let images = gsap.utils.toArray(selector),
      onLoad = e => {
        images.splice(images.indexOf(e.target), 1);
        images.length || callback();
      };
  images.forEach(img => img.addEventListener("load", onLoad));
}
onLoadImages(".lazyload", ScrollTrigger.refresh);

But of course that won't work if you're only loading each one when the scroll reaching a certain position. 

 

I have made some improvements in the next release which I'm using in this fork: 

See the Pen KKZovwj?editors=0010 by GreenSock (@GreenSock) on CodePen

 

Does that behave more like what you hoped? 

  • Like 2
Link to comment
Share on other sites

  • 1 month later...
On 4/7/2022 at 7:07 AM, GreenSock said:

You had a typo in your code that was throwing an error. I'm not sure why you were trying to call .refresh() on the smoother's ScrollTrigger (before your images even loaded). 

 

I didn't realize you were using a different library and only loading the images on-demand. In that case, yes, you'd need to at least call .refresh() on the individual ScrollTrigger associated with that newly-loaded image.

 

Originally, I thought you were just starting the load of all the images after your page loaded (without the images), so this is what I was talking about: 

function onLoadImages(selector, callback) {
  let images = gsap.utils.toArray(selector),
      onLoad = e => {
        images.splice(images.indexOf(e.target), 1);
        images.length || callback();
      };
  images.forEach(img => img.addEventListener("load", onLoad));
}
onLoadImages(".lazyload", ScrollTrigger.refresh);

But of course that won't work if you're only loading each one when the scroll reaching a certain position. 

 

I have made some improvements in the next release which I'm using in this fork: 

 

 

 

Does that behave more like what you hoped? 

That works like charm for me! 

  • Like 1
Link to comment
Share on other sites

  • 1 year later...
On 4/5/2022 at 10:57 PM, walpolea said:

I ran into the same issue with a tabbed component changing the content height. The only solution I found was to dispatch a resize event which ScrollTrigger refreshes values on pretty gracefully.

window.dispatchEvent(new Event("resize"));

 

This also works as images lazily load in, but there is some undesired jank as things recalculate while the scrolling is mid-tween

document.querySelectorAll("img[loading=lazy]").forEach((i) => {
  i.addEventListener("load", (e) => {
    window.dispatchEvent(new Event("resize"));
  });
});

THANK YOU SOOOO MUCH!!!!! ❤️

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