Jump to content
GreenSock

wpsoul

ScrollTrigger doesn't work properly on page with lazy load images

Recommended Posts

I try to drop ScrollMagic, everything works correct and easy to convert, but one problem is too critical. 

I have some lazy load images. And ScrollTrigger detects position of Element with wrong place if there are lazy load images on page. But if I resize window, position becomes correct. https://monosnap.com/file/FboOazk2EhmlsR5frWGNtUjgInRlhF

 

I think it's because scrolltrigger calculates height based on height attribute of images, but they can be resized in window after lazy load is working. 

 

Is any way to recalculate positions of elements or calculate them after all other scripts make job? I don't have the same problem in ScrollMagic

Link to comment
Share on other sites

Hey wpsoul. This is because ScrollTrigger bases its calculations on the elements when you create the ScrollTrigger. Generally it's a good idea to wait to create the ScrollTriggers until the image has loaded. Alternatively, you could call ScrollTrigger.refresh() after they load.

 

Another alternative is to use the width and height attributes to give the images a basic shape. That way you don't have to wait for the images to load to create the ScrollTriggers (though it's not a problem if you do wait).

  • Like 1
Link to comment
Share on other sites

yes, this is correct. Problem is that image has height attribute, but it's not always the same as real height in viewport, because all images are responsive. So, I think I need opposite - I need to prevent calculation of images from height attribute. I  also don't understand why ScrollMagic and waypoints have no such problem. Or as alternative, how to recalculate ALL scrolltriggers at once? Is ScrollTrigger.update() working for all instances?

Link to comment
Share on other sites

7 minutes ago, wpsoul said:

I  also don't understand why ScrollMagic and waypoints have no such problem.

Without seeing the code it's impossible for us to say but my guess is that ScrollMagic does a bunch of extra work that ScrollTrigger doesn't do. It's possible it's smart about it but from what I've seen in using people using ScrollMagic it's not very efficient.

 

ScrollTrigger.update() would cause ScrollTrigger to check if it needs to update every image, yes. As for handling responsiveness, as you've seen ScrollTrigger handles that automagically.

Link to comment
Share on other sites

I made demo for you.

See the Pen NWxaONx by igor-sunz (@igor-sunz) on CodePen

 

I tried to attach event and try to add ScrollTrigger.update on window load - it doesn't work. Always, show me wrong position of element

Link to comment
Share on other sites

4 hours ago, ZachSaucier said:

Alternatively, you could call ScrollTrigger.update() after they load.

I think you meant ScrollTrigger.refresh().

 

Just to be clear, update() merely checks the current scroll position against all the ScrollTriggers (cheap) whereas refresh() is what actually measures where all the start/end values should be (more expensive). In other words, if you set start: "top bottom", refresh() is what will actually figure out where the top and bottom are, where the intersection points would be with the scroller, etc. Then update() asks "is this scrollbar between those positions?"

 

3 hours ago, wpsoul said:

I tried to attach event and try to add ScrollTrigger.update on window load - it doesn't work. Always, show me wrong position of element

I didn't see any such code in your demo. Did you remove it? 

 

I didn't notice any odd positioning either. It seemed to work exactly the way I'd expect. What am I missing?

  • Like 1
Link to comment
Share on other sites

4 hours ago, ZachSaucier said:

use the width and height attributes

Without using both the width and height attributes on the img, there's no way for any tool to determine what the responsive dimensions are going to be before the imagse are loaded. In your demo it appears you're only setting the height to 100 with no width attribute. Also, lazysizes seems a bit overkill for lazyloading on scroll, when you could use ScrollTriger to do the same thing without loading another library or adding another scroll event listener function (or if you don't like that, using intersection observer, would also cut your code/lib dependency down).

  • Like 3
Link to comment
Share on other sites

8 hours ago, GreenSock said:

I didn't notice any odd positioning either. It seemed to work exactly the way I'd expect. What am I missing?

 

Try to reload page, sometimes it's correct, if window was resized, but mostly it will be too far bottom

https://monosnap.com/file/WMlmqn3d4dGkJKszgUJwCzRuIGbWbl

 

8 hours ago, elegantseagulls said:

Without using both the width and height attributes on the img, there's no way for any tool to determine what the responsive dimensions are going to be before the imagse are loaded. In your demo it appears you're only setting the height to 100 with no width attribute. Also, lazysizes seems a bit overkill for lazyloading on scroll, when you could use ScrollTriger to do the same thing without loading another library or adding another scroll event listener function (or if you don't like that, using intersection observer, would also cut your code/lib dependency down).

Problem is not in width and height attributes, problem is when height attribute doesn't the same as real height in viewport. For example, it's resized by css or height of container. And this scenario is almost on all complex sites, because images must be responsive. I can't use Scrolltrigger for lazyloading, because I am building gsap app for existed wordpress theme. Lazysizes script is recommended by google and it has one important thing which is not available in Scrolltrigger, it's working correctly on ajaxed elements and dynamic elements and has many addons, like iframe lazyload, background lazy load, support for responsive sizes, etc. 

 

P.s. I can't understand why position is correct if I resize window. Is Scrolltrigger refresed on window resize?

 

P.s 2 - Added ScrollTrigger.refresh() - no difference. Is any way to make it's working for detecting height after css resizing instead of using height parameters of image?

 

P.s. 3 - it looks like it's working correctly on first load. But if you reload page, you will see problem. Not sure why it's happening. 

 

Link to comment
Share on other sites

4 minutes ago, wpsoul said:

Problem is not in width and height attributes, problem is when height attribute doesn't the same as real height in viewport.

The reason for adding the width and height to the img tag has nothing to do the actual height and width of the image. The problem is that the pre-loaded placeholder doesn't have the same aspect ratio as your images because it doesn't know the width AND height. I think you'll find this article useful: https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/

 

From the above article:

Quote

Update! Times changed fast here, and to avoid lazy-load jank, all you have to do is put the correct natural width and height attributes on images and they will load nicely, even if CSS makes the image fluid with. So do it like: <img src="image.jpg" width="800" height="600">

 

You may also, for semantics and better SEO, want to use something with the picture element wrapping the image. I didn't fully suss out this article, but it looks like it should get you in the right direction: https://dev.to/stefanoverna/how-to-offer-responsive-progressive-images-in-2020-in-one-line-5fed

  • Like 1
Link to comment
Share on other sites

14 minutes ago, elegantseagulls said:

The problem is that the pre-loaded placeholder doesn't have the same aspect ratio as your images because it doesn't know the width AND height. I think you'll find this article useful: https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/

 

 

tested. Didn't help. I placed the same image in src and for lazy load. Now, scrolltrigger gives me wrong position which is above real position of element (previously it was under). So, it's not reason. I think I need function to reflow position after page is loaded. Something which is working when window resized. ScrollTrigger.refresh() and ScrollTrigger.update() don't work

Link to comment
Share on other sites

4 minutes ago, wpsoul said:

I placed the same image in src and for lazy load.

I checked your CodePen and it's still only using the height attribute. It needs both height and width. I added <img alt="demo" class="lazyload image" height="720" width="1280" src="https://unsplash.it/1280/720?image=100" data-srcset="https://unsplash.it/1280/720?image=100" /> as the images on your code pen, and get the expected results.
 

  • Like 1
Link to comment
Share on other sites

2 hours ago, elegantseagulls said:

I checked your CodePen and it's still only using the height attribute. It needs both height and width. I added <img alt="demo" class="lazyload image" height="720" width="1280" src="https://unsplash.it/1280/720?image=100" data-srcset="https://unsplash.it/1280/720?image=100" /> as the images on your code pen, and get the expected results.
 

 

No, it doesn't work. I added width parameter. There is no problem when I know image size, I can set their width. But user generated sites don't work in such scenario. I don't know real image size which will be uploaded, also, Wordpress generates different sizes for each resolution and images are resized via css. 

 

I repeat, problem is only when height parameter in css is set as auto (and this scenario is on ALL sites with responsive images) and final resizing is made by css. Scrolltrigger uses parameters from image settings and not from final rendering in browser. I need function which recalculate positions. refresh and update() don't work. 

Link to comment
Share on other sites

Hey wpsoul. Please make a minimal demo that recreates the situation that you're talking about where ScrollTrigger.refresh() being ran after the images are loaded doesn't fix the issue. It's hard for us to help blindly :) 

Link to comment
Share on other sites

3 minutes ago, ZachSaucier said:

Hey wpsoul. Please make a minimal demo that recreates the situation that you're talking about where ScrollTrigger.refresh() being ran after the images are loaded doesn't fix the issue. It's hard for us to help blindly :) 

 

it's already added in demo 

See the Pen NWxaONx by igor-sunz (@igor-sunz) on CodePen

Link to comment
Share on other sites

window.onload doesn't run after the images have all loaded. It runs before that.

 

If you run ScrollTrigger.refresh() once the images have loaded then it works :) 

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

  • Like 1
Link to comment
Share on other sites

Didn't know about this, thank you. But as I understand, this reduce perfomance a lot, because you trigger function for each image on page, page can have hundreds images if it's magazine site. Is any function which is called only once in the end?

Link to comment
Share on other sites

Sure, just count the number of images that are to be loaded and see if that many images have loaded each time that one loads. I do that sort of thing in this demo:

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

 

You might want to also have a "max time limit" in case one fails to load. You could do that by using a timeout that you clear if they all load.

  • Like 1
Link to comment
Share on other sites

Ok. Thank you. Found also solution special for lazysize script

 

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

Looks like it's working

 

Can you explain why there is no problem with waypoints and Scrollmagic. Does it mean that Scrolltrigger is calculating images more early than Lazysize script?

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

I can't say why given I haven't used waypoints or ScrollMagic much. I know that in some circumstances ScrollMagic checks regularly for changes (essentially a .refresh() in a setInterval). Not sure if that's what it does or if they have something that calls .refresh() if an image is the trigger and it hasn't loaded yet.

Link to comment
Share on other sites

3 hours ago, ZachSaucier said:

window.onload doesn't run after the images have all loaded. It runs before that.

 

Unless I'm missing something here, the window load event will fire when all the images have been loaded. 

 

Link to comment
Share on other sites

24 minutes ago, OSUblake said:

Unless I'm missing something here, the window load event will fire when all the images have been loaded. 

 

@GreenSock does ScrollTrigger listen for the load event? I guess even if it did, if someone adds window.onload = function() {}, then it screws it up.

Link to comment
Share on other sites

9 minutes ago, OSUblake said:

 

@GreenSock does ScrollTrigger listen for the load event? I guess even if it did, if someone adds window.onload = function() {}, then it screws it up.

Nope. It adds regular event listeners for for DOMContentLoaded, load, resize, and visibilitychange (and does a refresh() on all of those). However, the "load" one skips the refresh if you're currently scrolling (otherwise it could halt momentum scrolling on certain devices). 

 

3 hours ago, wpsoul said:

Can you explain why there is no problem with waypoints and Scrollmagic. Does it mean that Scrolltrigger is calculating images more early than Lazysize script?

I haven't looked at their source code for that but they may be using more expensive checks on each scroll event. ScrollTrigger is highly optimized to deliver maximum performance while scrolling. For example, some libraries might constantly check getBoundingClientRect() on each scroll event to see if things are in the viewport, etc., but that's very expensive. ScrollTrigger, however, only does the measurements on refresh(). Then, when you scroll it's merely checking ONE scroll position against the various start/end values (that were pre-calculated). Super fast and efficient. 

 

Does that clear things up? 

Link to comment
Share on other sites

1 hour ago, GreenSock said:

getBoundingClientRect()

yes, looks like it checks this and it's reason why it has no issues with image height. 

 

Anyway, solution was found. Now, I am testing perfomance on some real pages. And looks like it's no big difference in perfomance between SM and ST. In some points, ST is faster, in some points, SM. But, ScrollTrigger has more options, easy for understaning, much more flexible and has less size. So, definetelly, will move to ST for all future projects

  • Like 1
Link to comment
Share on other sites

42 minutes ago, wpsoul said:

Anyway, solution was found. Now, I am testing perfomance on some real pages. And looks like it's no big difference in perfomance between SM and ST. In some points, ST is faster, in some points, SM. But, ScrollTrigger has more options, easy for understaning, much more flexible and has less size. So, definetelly, will move to ST for all future projects

Thanks for letting us know the results of your tests. 

 

If there's anything SM is faster in (at least in any remotely significant way), I'd like to see it. 

 

Also, for the record ScrollTrigger checks getBoundingClientRect() too, but only when refresh() is called. That doesn't happen on regular scroll events. 

 

Glad to hear you're happy with ScrollTrigger and plan to use it for your future projects. We've got even more features coming in the next release :)

 

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