whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.03k stars 2.62k forks source link

Image `loading` on page load #10056

Open benmccann opened 8 months ago

benmccann commented 8 months ago

What problem are you trying to solve?

Lazy loading has performance benefits, but can be frustrating in practice. If you scroll down the page and see an image that hasn't loaded it's a worse user experience than if the image were already available. As a result, it forces developers to use placeholders, which can be quite cumbersome to implement and result in a poor user experience. The lazy loading behavior is particularly frustrating when stepping into the subway: https://twitter.com/Rich_Harris/status/1208040145385086982. If you load an article, lose connectivity, and then scroll to the bottom of the page it can be quite disappointing to find your images were lazy loaded and now are unavailable to you in what was a well meaning attempt to improve the user experience.

What solutions exist today?

I created Svelte's official image component and am considering implementing a solution to this in userland where we lazy load images by default and then switch them to eager after the page has loaded, which hopefully would be the best of both worlds by avoiding the shortcomings of lazy loading and implementation complexities of placeholders, but still capturing the desired performance benefits of reducing resource contention for rendering the initial viewport.

How would you solve it?

Add a new attribute value like loading=idle or loading=domcontentloaded

Anything else?

This may also address @zcorpan's similar request in https://github.com/whatwg/html/issues/8007

zcorpan commented 8 months ago

Why isn't using only eager images (maybe with fetchpriority="low" on ones below the fold) sufficient?

benmccann commented 8 months ago

Why isn't using only eager images (maybe with fetchpriority="low" on ones below the fold) sufficient?

Unfortunately, if all images are fetched eagerly it results in resource contention. I assume that's the reason lazy exists in the first place.

Below is an example showing that lazy loading speeds up page load. Eager loading of images: https://www.webpagetest.org/result/231207_BiDc5F_EM6/ Lazy loading images: https://www.webpagetest.org/result/231207_BiDcKD_EM7/

If you look at the waterfall for the original eager Web Page Test run and hover over the images, you can see in the popup that the priority is "medium" for images higher up and "low" for those lower down. I'll note that there is a distinction between prioritization and loading. "Loading" simply dictates when a resource is added to the request queue. When set to the default "eager", all images will be requested regardless of where they are in the page - that's the spec-defined behavior. Priority, on the otherhand, dictates how the urgency flag will be set on the outgoing request, which will be interpreted by the CDN/server. In this case, we're concerned about the loading behavior - the fact that all the images are added to the queue.

For others who come across this thread and might want to read up on the topic, here's an article about it: https://web.dev/articles/browser-level-image-lazy-loading

zcorpan commented 7 months ago

I'm told fetchpriority can also be a signal to the browser for e.g. resource allocation and quotas for parallel fetches.

Still, I accept that network congestion can happen even with fetchpriority, thus slowing down the first paint or first contentful paint.

My main concern is that it seems like browsers should be able and maybe better positioned to manage page load. But maybe hints like this are needed?

@noamr @yoavweiss thoughts?

yoavweiss commented 7 months ago

I'm told fetchpriority can also be a signal to the browser for e.g. resource allocation and quotas for parallel fetches.

Still, I accept that network congestion can happen even with fetchpriority, thus slowing down the first paint or first contentful paint.

One particular example where low priority won't help is when the images are fetched over a separate connection than some other resources on the page. In that case, the server serving the images would only get their requests (with low priority) and will serve them immediately, resulting in network contention with the other, higher-priority resources.

I wrote about this a bit in the past, with a halfbaked proposal that didn't make it very far. It seems that this feature request is aiming for a similar goal - kicking off a load only at a certain point in the document's loading lifecycle.

Generally, I think this is a problem worth solving, even if I haven't thought very hard about the use of the loading attribute for this.

^^ @pmeenan @nyaxt

smaug---- commented 5 months ago

loading="idle" wouldn't probably work too well, since there is often plenty of idle time also during page load. (And I wouldn't want "idle" have different meaning with loading attribute) loading="domcontentloaded" might be also problematic. Many of the resources are often loaded after domcontentloaded.

The document yoav linked has some initial ideas how to solve this, but I think those might be overly complicated. And there is the nice todo comment there "think about images" :)

benmccann commented 5 months ago

Thanks @smaug----. Can you clarify what you mean in terms of "many of the resources are often loaded after domcontentloaded" causing problems? E.g. do you mean if an image was dynamically added to the DOM after domcontentloaded that load would never be triggered? I was imagining it would just be loaded right away in that case

smaug---- commented 5 months ago

I mean that if the loading of a "semi-lazy" image was triggered at domcontentloaded time, it would affect negatively loading of other resources.

benmccann commented 5 months ago

Potentially. It would depend on the application. Many web pages won't load anything on domcontentloaded. Making it an attribute that the developer controls would let them decide what is best for their application and we could provide guidance on resources like MDN and web.dev to consider what else might be being loaded. And I would think that even if developers blindly set it on every image that it'd be an improvement from today on average

noamr commented 5 months ago

Seems like looking at this from the point of view of images misses a lot of context. At any given time, those below-the-fold images can compete with other resources (e.g. deferred modules that import other modules), and it's not clear whether they should take precedence or wait. For example, the deferred module could be loading resources for the options menu - the browser doesn't have context whether that's the case, and what the user is going to do first, click the options menu or scroll down.

If we do something "idle" ish, where these images only load if there are no pending fetches, there could be situations where this is never the case (e.g. polling) and those images would remain lazy.

So unless we come up with some elaborate declarative structure for what loads after what, my sense is that setting the image's loading attribute from lazy to eager using JavaScript is perhaps not a bad solution, as it gives this power to the application rather than try to be too clever in the browser layer.

chrishtr commented 5 months ago

(removing agenda+ because @kara wants to follow up on the points raised already on this issue. Thanks all for your feedback!)

gyurielf commented 3 months ago

Hello there! Any update on this ? :)