Lazy loading images is currently achieved via JavaScript libraries; see this post for a recent overview of such libraries. Wikimedia is even experimenting with using a service worker for this.
Are there any proposals to enable image lazy loading declaratively in HTML (or even HTTP)?
This is a subject Iām very passionate about, because I feel that if thereās no need to use javascript libraries (which are unable to completely do this task because thereās no way to subscribe to a āprintā event and download the images then, and donāt work without javascript without a cumbersome <noscript> section), we can have a really fast web because more people will lazy load their images.
This is especially important in mobile browsers, where downloading images comes at a performance (uses up paralell connections to a server, delaying other important resources) and actual monetary cost.
This is implemented in Internet Explorer 11 (and maybe Edge) as
<img src="whatever.jpg" lazyload>
Which I believe was taken from the aforementioned (and dead, sadly) Resource Priorities spec. Sadly, the replacement, Resource Hints, has scaled back and is only about giving URLs to the lookahead preparser ahead of time.
Should the exact behavior be specifiable? Do you want to load images when the network is otherwise idle, or only once the image approaches the viewport? Something like lazyload="visible" or lazyload="idle" could work. Such behavior might require width, height, and sizes attributes so the browser doesnāt have to reflow after fetching the image.
We have a few attributes already designed for loading and execution behavior. Maybe they should get expanded to all request-making elements, like:
async and defer determine when a script is executed, not loaded, so I donāt know if they make much sense applied to <img> (which, if you equate execution with display, are already kinda async?).
There are two, related goals here:
Load critical bytes first (aka, bring the SpeedIndex down)
Donāt load unnecessary bytes at all (aka bring the
bytes-over-the-wire down)
Anything that did #2 well enough would also achieve #1, but it seems hard to do perfectly. Trying to load images Just-In-Time⢠is going to mean some images get loaded noticeably late or not at all in at least some edge cases (e.g. initial load on a train, scroll in a tunnel).
All of the JavaScript libraries in the link up top, and every library Iāve seen, go for #2, so it feels more important?
The runtime may choose to delay or prioritize resource loading based on
the viewport position, system resources, connection bandwidth, or other
factors.
I think the idea is, if the user decides they arenāt interested in an article while reading it, theyāre not penalized for loading images theyād never see.
Still, itās worthwhile just trying to get Goal #1 by itself, so if this complicates matters unnecessarily, just leave it for later.
Developer convenience would mean this pattern is more often used
Cons:
Fear of abuse that would cause overall perf regressions.
All in all:
A lazy attribute has no (significant) perf advantage over script-based solutions
The browser would have to wait until layout is complete in order to know if a certain resource should be fetched or not.
A ServiceWorker based solution can resolve the problem for the āJS is not runningā case, even if with some overhead
IntersectionObserver would make it easier to implement a JS loading scheme without scroll-related hacks
The main problem with both a JS based solution and a lazy attribute, is that both would require you to add to markup which images should be lazy loaded, which is something that can change based on the viewport
thereās a good chance that having a commonly used lazy-loading solution (native or JS based) would result in regressions on that metric if overly used, since in-the-viewport images are likely to be marked as lazyload and delayed.
On that front, the browser should prioritize in-the-viewport images over out-of-viewport ones, and download everything needed for visual completeness first. Iām not sure lazy loading would help here.
Sometimes (eg, in a carousel) the author definitely knows that certain images wonāt be visible on first load, no matter what the viewport looks like. A non-hacky way to explicitly request deferred loading for just those images (without marking up imgs-without-srces or whatever) would be useful.
But my hunch is that itās much more common for some authors to want to slap data-lazys onto large swaths of maybe-visible or probably-not-visible images by default, which would sometimes result in the SpeedIndex regressions which you describe (with the tradeoff being that people who donāt see all of the images on the page donāt load them).
I should compile some links of popular sites that lazily load to better understand how itās being used in the wild, now, and why⦠but Iām about to leave for a weeklong vacation.
On that front, the browser should prioritize in-the-viewport images over out-of-viewport ones, and download everything needed for visual completeness first. Iām not sure lazy loading would help here.
This sounds ideal, but would be impossible without waiting for layout, which would probably cause regressions?
To start, letās clarify what ālazy loadā means⦠I see different folks using different definitions on this thread.
As a prioritization signal that affects the order in which images are loaded.
As an āon-demand loadingā signal that allows the user agent to skip loading and/or load image when some criteria are met (e.g. visibility).
For (1), Iād argue that ālazyloadā is the wrong concept; this is prioritization, plain and simple. We need an API that will allow developers to customize the network-layer priority of any given resource fetch:
override default UA prioritization logic - e.g. not all images are same priority; some images are just as important as blocking CSS; some CSS is less important than images; etc.
this API is not restricted to images, it applies to all fetches initiated by the browser.
this API allows developers to downgrade and upgrade priority of fetches.
(Side note: IEās implementation of lazyload is prioritization⦠All it does is downgrade the priority of the image in their net-stack.)
For (2), I remain very skeptical that this is something that browsers should take on. There is a lot of magic assumptions here that donāt stand up to scrutiny of being a platform featureā¦
Deferred resource loading is not an unconditional win for the user. Waking up the mobile radio is very costly and will consume more energy; it can cause delayed rendering; it can cause more reflows, etc. Perhaps youāre willing to sacrifice some of these if the user is sensitive to amount of downloaded data, but thatās just one consideration of many - e.g. type of network, type of resources being fetched, etc, can change the balance of the equation.
Deferred resource loading ādone wellā is highly application specific. For example, if youāre building an infinite scroller you may want to tweak how far you prefetch based on users scroll position - e.g. preload next item vs three screens ahead vs ⦠whatever logic makes sense for your app.
Deferred resource loading use cases are not restricted to images. As Yoav pointed out earlier, the logic may change based on current layout and active breakpoint ā element attributes canāt account for this, at least not easily.
Long story short, I think this space is too complex to reduce it to one or several keywords that you sprinkle on your elements. The platformsā job here is to give developers the tools to build own ādeferred loadingā logic. Some of these building blocks are:
A way to efficiently query element visibility information - see intersection observer.
A way to prioritize fetch requests via ~fetch prioritization API - addresses (1), helps (2).
A way to determine if user is sensitive to data use - see save-data.
A way to determine connectivity information - see NetInfo.
A way to schedule processing/decoding/whatever without causing jank - see requesIdleCallback.
ā¦
The above is not a complete list, but those are some of the most critical building blocks that enable developers to build own ādeferred loadingā implementations that make sense for their particular use case.
One frustration that comes up a lot is that we canāt have things like
<object type="image/svg+xml">
<img>
</object>
without penalizing users with a double-download. The ability to āturn off the preparserā might not be an ability browsers want to give to developers, but itās definitely frustrating that the built-in, scriptless, semantic fallback abilities of HTML are rather useless when preparsers clobber any performance benefits from using them.
I personally have talked with a few people who want lazyload for a reason like that, so maybe thatās yet another tangentially-related thing that is getting lumped in.
That is already what Blink/Chrome does. Images start their lives at lowest priority, and get upgraded as they become visible. That means that if there arenāt more important resource, images will get requested according to their order, but if there are, they are requested only once their priority gets bumped.
Itās per-spec that img still loads even inside object, but we could change the spec (assuming itās Web-compatible enough). Similarly for img in video and audio probably.
A little browsing through a the results of a hacky HTTPArchive query shows that the most popular pages using anything called ālazyloadā are all doing deferred loading, either because they are long pages stuffed with images (lots of catalog-style shopping sites and news sites) or they have carousels.
Hereās my argument for ādeferredā lazyloading in a nutshell: images that definitely or very-probably wonāt be visible on pageload shouldnāt be loaded until theyāre needed. There should be a simple way for authors to achieve this without invalid markup or transparent gifs. Tens of thousands of sites are currently using this library or something like it to serve up <img>s without srcs. Thatās a problem!
So let me see if I understand: the speculative pre-parser combs through a page and compiles a list of all of the external resource URLs. It sticks images at the bottom of this the list and kicks off loading as many of these resources as it can. If the queue still exists after layout is complete, images that are in the viewport are bumped up.