Comments (15)
Very interesting, thanks for sharing.
Will need to do some testing
from blazy.
Images seem to stall out on loading on my iPad5 (Air) iOS7.0. When I update I'll edit this post.
from blazy.
Any news tom? I tested on ipad5 with iOS7.1. No issues
from blazy.
I'm also working on this issue. First of all, I'm on an iPad, and I do replicate the problem:
1 - Touch & hold at bottom of viewport
2 - Drag up to scroll down, but do not release
Actual results: I see placeholder images/broken images, and no loading is triggered until I release
Expected results: trigger loading as soon as I can "see" the image [regardless of my finger being remaining pressed on the screen or not].
Now, I changed the code to bind touchmove
, which yields no observable changes to the behavior at all. Although by debugging I can see that by binding touchmove
, your function validate()
gets called continuously as I drag, via the throttle()
method. Furthermore it triggers loadImage()
on every image immediately as it enters my viewport, without my releasing... but what doesn't happen is the browser does not show those images until I release. It does however preload them.
It looks like this is because when an image is called with loadImage()
it creates an Image
object in javascript for purposes of preloading, and attaches an onload
callback to that image object, which updates the actual DOM image upon success. It is perhaps the execution of this onload
callback that seems to be queued until I "touch release". The article does mention timeouts & intervals are queued, so this seems to be the same problem. I also found another article about JS image loading, where one commenter states:
iOS currently pauses all JavaScript during scroll to divert CPU power to rendering the page.
I'm not sure what this means, but its not literally true. I can write out a timestamp to a div
"ontouchmove" and view the number continuously changing in a rapid fashion while I'm moving my finger, before releasing, so this proves the whole JS thread isn't blocked.
I then replaced your img.src = src
line with ele.src = src
which will set the src
on the image tag in the DOM immediately, circumventing your preload indirection. I also append some debug info to a div upon doing this:
ele.src = src;
$('#ios').append('<br />' + src);
What I observe is that while my finger is held down on the screen scrolling, I see the URLs for the images logged to that div continuously, indicating loadImage() is being called on each image as it enters the viewport - however it seems the images still don't showup until I release my finger.
One difference worth noting is that when I set the src
on the element & circumvent the preload logic, there is more latency before the images are loaded. To me what this suggests is that JS does execute while scrolling, and you can load images in the background while scrolling with:
var img = new Image();
img.src = 'foo.jpg';
and that foo.jpg will be prefetched while scrolling. However it seems iOS is blocking the DOM updates, or the repainting of the viewport. I tried changing the code from:
ele.src = src;
$('#ios').append('<br />' + src);
to this
ele.src = src;
$('#ios').append('<br />' + ele.src);
What this is supposed to test out is did the HTML attribute change. If the HTML attribute change is what was queued, I'd expect to get NULL
or whatever my placeholder src
was. In fact I get the new URL, which seems to indicate that HTML attribute for the img's src is updated instantly while scrolling, as well as the browser fetches the image resource (as suggested by the fact the images load 'instantly' after releasing my finger). So from all of this, I can only assume that iOS is queue the redraw within the browser (albeit still executing javascript).
It's interesting the text in the div is updated though & not queued. Do they queue only certain DOM updates, and is there a way to abuse that to force our images to load? I don't know and I've run out of things to try at this point. Although I have now learned their reason to make the updates queue while scrolling. Its apparently to preserve battery/CPU.
I guess some developers have worked around this by creating libraries that disable scrolling in the browser, and render a "fake" scrollback which is entirely JS based. Not something I'm fond of though.
from blazy.
Great sluthing @joshribakoff
from blazy.
Actually I think I cracked the cookie guys! (or whatever the saying is).
So, like I said above I found its strange I can append HTML to a div, but not update an HTML attribute of an existing element. I tried changing just now:
$('#ios').append('<br />' + ele.src);
becomes this:
$('#ios').append('<br />loaded: ' + '<img src="'+src+'" />');
And while holding my finger on the screen & moving, I see the images load into my debug div right away without releasing my finger! So the trick is to insert new DOM elements instead of manipulating existing ones [in conjunction with binding to ontouchmove] for iOS.
So all you need to do is insert a new img element below the original img, and remove the original img tag. These types of updates are repainted right away, whereas changing the src attribute on an image tag is queued.
PS... I am on iOS 7.1
from blazy.
the trick is to insert new DOM elements instead of manipulating existing ones [in conjunction with binding to ontouchmove] for iOS
Great find. Could be a performance nightmare; all the reflows, so likely iOS-only workaround. I tried to find on jsPerf a test, but no luck.
from blazy.
There's actually no reflow, since blazy recommends a div wrapper with a padding-bottom to retain the space in the flow of the page.
Here's another observation:
$('#ios').append('preload: ' + '<img src="' + src + '" /><hr />');
This works, the text & image is appended immediately while scrolling (never releasing my finger) I see the images append to the div.
This does not work, seems replacing a div's contents is queued.
$('#ios').html('preload: ' + '<img src="' + src + '" /><hr />');
This also does not work, seems that the presence of CSS is making the repaint queue up:
$('#ios').append('preload: ' + '<img src="' + src + '" style="max-width:50px" /><hr />');
Also even when I've hit the sweet spot on things working, things intermittently don't work, sometimes the updates don't batch out until I release my finger.... but by tweaking the code to get in the sweet spot things seem to work 90% of the time.
So my sweet spot so far is to append a new image, with no styling, to the wrapper div. Your CSS should be written in such a way that appended images obscure any other images in that container. Something like this works for me:
(LESS)
.lazy-img-container {
max-width:100%;
position:relative;
img {
position:absolute;
width:100%;
height:100%;
}
}
I should also note that there seems to be a bug where loadImage(ele)
is called twice for a given image. Doesn't seem to affect the viability of this solution, but should be fixed separately.
from blazy.
Very interesting and nice debugging. Will need to do some testing myself, just really busy at the moment. I'm not thrilled about the workaround :) I foresee some inexpediencies.
Have any of you tested on an android tablet?
Thanks for all the testing, I really appreciate it
from blazy.
I'm running into the same issue now while trying to implement this. In doing some basic testing, every user I've observed rapidly scrolls around my page and rarely fully released their finger from the screen or let the momentum of the scrolling come to a stop. So images barely ever have a chance to load…
Any progress on this front? : )
from blazy.
No Im afraid not. It's a "feature" in iOS. iOS devices freeze DOM manipulation during scroll, queuing them to apply when the scroll finishes.
Solutions at the moment is either go with @joshribakoff approach where you append new image markup or override the native scroll.
from blazy.
As of iOS8, the scroll event fires continuosly & all DOM updates go through right away.
from blazy.
Hey Josh.
Yes I read that and I'm pretty sure I tested it when iOS 8 was released but no change. However now it works wonderful in 8.1.x.
Anyone still running 8.0.0 and able to test?
from blazy.
Not fixed for Cordova web views :(
One caveat for Cordova developers
Although Apple implemented this change in iOS Safari, as well as its new WKWebView control, it did not change the scroll behavior in its old UIWebView control. And because of a major bug in the replacement WKWebView control, the Cordova team cannot upgrade to WKWebView yet.
This means that at the moment Cordova apps running on iOS 8 continue to pause JavaScript execution, and will continue to until Cordova can upgrade. And this doesn’t just affect Cordova apps. Any iOS app that uses web views — including Facebook, Twitter, and Chrome for iOS — will get the old behavior until they upgrade their apps to WKWebView. So yes, that means you could get different behavior opening the same URL from different iOS apps depending on which API they use internally.
Update (September 25th): Commenter Ben Kennedy found that, for whatever crazy reason, the old scroll behavior also applies to home screen web apps. So to summarize, apps that run in Safari or in a WKWebView get the new scroll behavior, apps that run in a UIWebView or in a home screen web app do not.
from blazy.
Hey @jDeppen.
Yes I noticed it in chrome for IOS. Thanks for the explanation.
from blazy.
Related Issues (20)
- srcset bug in Chrome & FF
- Not working on hidden tabs HOT 1
- Make bLazy available via composer? HOT 2
- Not working with webpack Encore HOT 1
- Issue in Safari & Firefox (page stays blank for 5-7 seconds)
- Parsing data-src with URL parameters HOT 2
- Background images data-src-small HOT 1
- Not working on Android 'data-src'
- Is an 'alt' attribute required in img tags? HOT 1
- What is the meaning of "loadInvisible"? HOT 3
- Current project status HOT 2
- not working in silder HOT 2
- Not working with older IE browsers versions 5 & 7 HOT 2
- Is it possible to use JS to alter src to data-src on iframe? HOT 2
- invalid issues
- Video and poster
- Cannot exclude featured image HOT 2
- Default lazyload image example Not working
- Safari iOS 15.4.1 lazy loading not working. HOT 2
- Doesn't work with pagination
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from blazy.