aFarkas / lazysizes

High performance and SEO friendly lazy loader for images (responsive and normal), iframes and more, that detects any visibility changes triggered through user interaction, CSS or JavaScript without configuration.
MIT License
17.52k stars 1.73k forks source link

Some images with lazyload class sometimes get stuck in the lazyloading state #311

Closed kireerik closed 6 years ago

kireerik commented 8 years ago

Some images with lazyload class in some cases get sucked in the laziloading state with the laziloading class, and they never get the lazyloaded class. However the images are loaded by the browser, but they are not displayed.

aFarkas commented 8 years ago

Thanks, I clearly need more information:

  1. url to a testcase/showcase?
  2. in what browser(s) does this happen?
marcelgwerder commented 8 years ago

I can confirm that there seems to be something wrong with either detecting when the image is in the "lazyload viewport" or when it is fully loaded. Sometimes my images don't show up on the page even when they are in cache and should be there quickly. Although I cannot yet provide more info other than that this happens for me on Chrome 53.0.2785.143 m and that we're using responsive images with the picture element. I'll try to reproduce this somehow and give more info...

aFarkas commented 8 years ago

Why can't you distinguish between the situations "wrong viewport detection" and "wrong loaded detection".

At the end I really need a testcase (you don't even need to reduce this a full page/app is enough for me to figure it out).

marcelgwerder commented 8 years ago

Because it happens infrequently and when I open the dev tools to see what exactly is going on, it usually also causes the images to show up.

We use the lib on https://energy.ch and it's also where we got the problems sometimes.

aFarkas commented 8 years ago

So we have a kind of a schrödingers bug. I tried your page and couldn't reproduce it. I will keep on trying.

But I can already give you something to check for yourself. Chrome sometimes seems to handle "pictured" img elements without initial src and srcset attributes quite strange (i.e. all those conditions have to present).

Can you try to add src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" and check yourself wether this helps.

aFarkas commented 8 years ago

Just rechecked an empty alt="" doesn't help. Try to add the src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==".

kireerik commented 8 years ago

Hi @aFarkas,

Thank you for your questions!

  1. I am using lazysizes on one of my sales page, where I advertise an Android 6.0 phone with a great price for the value for Hungarians. Each image has an initial src tag like this: src="image/placeholder.png". You can experience the reported issue in the slider, which is using Swiper. Elevatezoom is also used on those images in the slider.
  2. Windows 10 64bit, Google Chrome 54.0.2840.71 m However I can also repruduce the issue under the following browsers: Mozilla Firefox 49.0.1, 49.0.2, Opera 39.0, 40.0, Microsoft Edge 38.14393.0.0 and Microsoft Internet Expplorer 11.321.14393.0

The reported issue happens when I select a color variant other than the initially selected one. Than I hover the mouse on a thumbnail image, which is on a newly added slide. Than I hover on the image above the thumbnail and the issue occurs.

Thank you for checking the issue in advance!

aFarkas commented 8 years ago

@kireerik

Your issue is not really comparable with the issue of @marcelgwerder. In case of @marcelgwerder I assume a browser bug, that hopefully can be worked around by using a valid src or srcset attribute.

You bug seems more like a JS conflict. I assume the following line(s) produce this:

activeSlide.data('original-content',activeSlide.html()).html(newSlide.html())
/*....*/
previousSlide.html(activeSlideContent).data('original-content', activeSlideContent)
activeSlide.html(activeSlide.data('original-content')).css('background-color', '')

The problem is that you constantly destroy the DOM elements. You can workaround this by either working with the real nodes:

activeSlide.data('original-content',activeSlide.children().detach()).html(newSlide.children()) 
/* ... 
Don't forget the other two lines.
*/

Or by re-adding the lazyload class:

activeSlide.data('original-content',activeSlide.html()).html(newSlide.html()).find('.lazyloading').addClass('lazyload');
/* ... 
Don't forget the other two lines.
*/
kireerik commented 8 years ago

Hi @aFarkas,

Thank you for your detailed reply! I really appreciate your work!

I re-added the lazyload class, so now my implementation works perfectly.

I only needed to re-add the class at one point, when you hover the mouse over the big image from the thumbnail.

I think now we can close this issue, because it is not closely related to lazysizes, or is it?

yairEO commented 7 years ago

@aFarkas (please read the update first or don't read anything and not waste your time, since I understood the issue)

I'm also experiencing this. I have no user-interaction with the images, and they are in the format of <picture>..source.. img.. </picture>. they are rendered from a javascript template file and injected into the page, after a REST call is made to get the URLs needed for that page.

I am seeing this when my website is being prerendered and the class of the img is changed to preloading and not to preloaded. very annoying. and I do give enough time (tried a very long timeout) for the page to "settle down" before telling the prerender the page is ready.

11111

I am also using (picturefill)[https://github.com/scottjehl/picturefill] if that's any helpful information

Update

Ok, I think I understand the situation, the class cannot ever be changed to preloaded because that requires the image to actually load, and that is happening way after the preloader server was fired and prerendered the page, at that point javascript does not exist anymore. I would have to find a way to manually change all the classes.

Update2

Seems like, for some reason, lazysizes does not work at all on some pages, even though I guaranteed the integrity of the markup (printed the innerHTML of a picture element on the screen and even called window.lazySizes.init(); but it just doesn't do anything. (still using data-srcset without modification. with class lazyload present on the img itself. odd!

decodez commented 7 years ago

Any possible workarounds for this issue? I have the same issue with a new project but it is only in IE. The first images in the viewport gets loaded and the rest of them stuck at class 'lazy-loading'. Any update one this issue? pls help. Thanks

jnahlovsky commented 7 years ago

Hi, I'm experiencing the same issue after update from v.2.0.0 to 4.0.0. recently (on all major browsers including Chrome). Not on every place, but some images have still "lazyloading" state class. Only that class with its own style cause the zero opacity and makes image invisible. This is only happening when I'm directly on the same screen while lazyload is applied. When I'm scrolling from the top after refresh, everything works well. One more note is, that those images are loaded dynamically with Angular. Any ideas how to fix it (I would rather some systematic solution rather than some hotfix mentioned above - just find "lazyloading" class and replace it with lazyload? Cheers.

aFarkas commented 7 years ago

@VonSandberg Can you give me a URL to check this bug?

aFarkas commented 7 years ago

@VonSandberg

It would be extremely important for me to get access to a testcase or the real site or something to see this regression bug. Please help!!!

jnahlovsky commented 7 years ago

@aFarkas I know. Unfortunately, I'm not able to easily demonstrate it (internal project, quite huge).

PROBLEM: Angular process with lazyloading at the same time. Just guess. FIX: We ended up with the simple window.ready function calling init().

woutervanerp commented 7 years ago

@VonSandberg To bad this solution isn't working for me. With the state changing i'm stil getting stuck on the lazyloading even after i call the lazySizes.init() in window.ready.

aFarkas commented 7 years ago

@wplerp Maybe you forgot to disable the auto init feature?

<script>
window.lazySizesConfig = window.lazySizesConfig || {};
window.lazySizesConfig.init = false;
</script>

<script>
onMyCallback(lazySizes.init);
</script>
woutervanerp commented 7 years ago

@aFarkas Yes! that fixed it. Thank you for your fast response!

jakedowns commented 7 years ago

fwiw, had a similar issue with Vue, had to delay lazySizes.init until after Vue had mounted our SSR dom elements

ullmark commented 6 years ago

@jakedowns I can confirm getting issues with images not leaving lazyloading with Vue. (My use case is lazysizes + picturefill + bgset-plugin, but getting the same issue. If I disable Vue, everything works as it should)

moldedjelly commented 6 years ago

I get this same issue of lazyload elements stuck with class "lazyloading" but can see that the image has loaded in dev tools (network). If I clear my browser (Chrome) cache and load up the page, most times the thumbnails have this issue... eg.: http://edwinacorlette.com/artists/clara-adolphs Tried the manual init tricks listed above and still have this issue.

moldedjelly commented 6 years ago

I was using HTML commenting to hide some HTML from being indexed - content that I write into the page on load so I think the rewriting of html (using .html(content) inside document.ready) was causing issues since lazyloading was initialising from the head element - but not entirely sure this was the issue. I did fix it though by doing this at the end of my jquery document.ready script: $('.lazyloading').addClass('lazyload').removeClass('lazyloading'); I did this to try and get any elements stuck in lazyloading to retrigger their loading etc. This seems to have fixed the issue. I thought about delaying the init of lazysizes until the end of document.ready but like the idea of images starting to load ASAP.

aFarkas commented 6 years ago

@moldedjelly This is obvious the reason for your issue. At this point the lazyload class is removed, but the DOM references to the loading elements is destroyed.

The best thing todo is to rewrite you HTML by keeping the lazyload elements. i.e.: Do not use innerHTML and similar method but use dom mutation methods like apendChild, setAttribute etc..

code-mattclaffey commented 6 years ago

I am still getting this issue on version 4.0.1 on IE11

capture

On this url - https://www.hillarys.co.uk/blinds-range/roller-blinds/

There is a component further down to "A Roller blind for all reasons" I am getting the lazyloading class. This is slowly becoming a sitewide issue. Am I implementing it incorrectly?

Thanks

Matt

ugrupp commented 6 years ago

Same issue here on IE11. I feel like this has only appeared in the last couple of days, i swear it used to work.

aFarkas commented 6 years ago

@code-mattclaffey Use data-srcset on the img element instead of data-src or use a last source element without a media attribute condition.

code-mattclaffey commented 6 years ago

@aFarkas why would adding data-srcset on the img tag work? I have added it in and it did seem to work but in the documentation it states that the image element should have data-src applied to it? Is data-srcset the attribute to use for picture elements that have different sources?

aFarkas commented 6 years ago

@code-mattclaffey This is a very specific issue that has to do with how loading in general works and only applies to the following situation:

  1. you are in a browser that does not support picture and you are using a picture element
  2. you are using a polyfill
  3. you have no srcset/data-srcset on your img element
  4. the last source has a media or a type attribute

The problem is if I add the src element to img it downloads this immediately even if this src is overwritten by the polyfill. This is why I don't change the src in those browsers.

With my newest change I will automatically mirror the data-src to the srcset element in those cases.

0xc0d3r commented 5 years ago

Hi,

Even we are also facing the same issue.

Screenshot 2019-03-18 at 15 33 35

Though we scrolled down to the page, src attibute is not set and network requests were not triggered for images

TIA

aFarkas commented 5 years ago

@0xc0d3r Pretty sure it is not a lazysizes issue. But you always need to provide a testcase or at least a link to the site, otherwise I can't reproduce the problem.

aFarkas commented 5 years ago

@0xc0d3r

lazySizes is not included on this page.

0xc0d3r commented 5 years ago

@aFarkas Thanks for the prompt response. <3

I'm removing the comment which has the link.

bkarlson commented 5 years ago

I still encounter this issue with lazysizes and vue on re-used router views (including :key='id' did not help, but it's a good practice anyway). The issue seems to arise when Vue re-uses same img tag with the same :key. Lazysizes does not remove .lazyloading and in Network tab those images are marked as "Stalled". This affects only a bunch of images that have been preloaded by LS earlier, i.e. images well below the fold are still lazyloaded fine.

I'm not sure who's the culprit here: vue, lazysizes or Chrome, but nor plugins neither any LS configuration options helped to alleviate the issue.

So I ended up building a primitive cache within Vuex that tracks already displayed images (under assumption that they ended up in browser's cache) and once an image is in the cache, it won't be lazyloaded anymore:

  mounted() {
          const tempCache = new Set([...state.thumbsCache])
          response.data.pix.forEach(pic => tempCache.add(pic.id))
          state.thumbsCache = Object.freeze(tempCache)
}

In your template something like:

:src="thumbsCache.has(id) ? thumbURL(id): null" :data-src="//opposite logic"
enmanuelr7 commented 4 years ago

hi @aFarkas, i'm having this issue on https://dekora-angular.firebaseapp.com/home (mobile view). sometimes the image of the first item of the slides doesn't get to load (and sometimes the second). it happens about 1/10 times when i first load the page. I'm using angular 8. Greetings!

marshall993 commented 4 years ago

@aFarkas I'm just wondering why this issue was closed? This issue is still occurring in IE 11 (as shown in the attached screenshot below. Is there any solution to prevent the lazyloading class from getting stuck?

Image 2020-03-19 at 10 13 56 AM
sumitchoudhary08 commented 4 years ago

@aFarkas ,

My videos are getting stucked with 'lazyloading', instead of loazyloaded.

And when I inspect and change lazyloading class to lazyload, it gets to lazyloaded.

kindly let me know the fix for it.

amoralesdesign commented 4 years ago

Same problem here with Google Chrome, my first ten elements is lazyloading and not set the class to lazyloaded

zeppelinen commented 4 years ago

Same problem here with bgset plugin and slow response time from images CDN (~2 seconds).

ssoulless commented 3 years ago

This solved my problem, I just added the init in the $(document).ready callback

@wplerp Maybe you forgot to disable the auto init feature?

<script>
window.lazySizesConfig = window.lazySizesConfig || {};
window.lazySizesConfig.init = false;
</script>

<script>
onMyCallback(lazySizes.init);
</script>
gtempesta commented 3 years ago

@wplerp Maybe you forgot to disable the auto init feature?

<script>
window.lazySizesConfig = window.lazySizesConfig || {};
window.lazySizesConfig.init = false;
</script>

<script>
onMyCallback(lazySizes.init);
</script>

@aFarkas I don't know if it's due to the fact that I'm importing the library with webpack, but I don't have an available lazySizesConfig variable if I do

import 'lazysizes';
// window.lazySizesConfig will be undefined at the start and then an empty object
window.lazySizesConfig = window.lazySizesConfig || {};

In order to extract the config I need to do this instead:

const lazySizesConfig = lazySizes.cfg;

Apart from the that, your solution fixed my issue:

const lazySizesConfig = lazySizes.cfg;
lazySizesConfig.init = false;
window.addEventListener('load', lazySizes.init);