apache / incubator-pagespeed-ngx

Automatic PageSpeed optimization module for Nginx
http://ngxpagespeed.com/
Apache License 2.0
4.36k stars 364 forks source link

Chrome's Native Lazy Loading #1663

Open viktorix opened 5 years ago

viktorix commented 5 years ago

Chrome introduced native lazy loading recently. Would highly recommend implementing it as an alternative to the current lazy loading with beacons, and use beacons as a fallback for older browsers or those that might be still missing this feature.

https://web.dev/native-lazy-loading

Lofesa commented 5 years ago

Hi @viktorix Thats is a work to do. Recently I have talked with @jmarantz about this type of issue In mod-pagespeed PR #1899. I think the lazyload funtionality must take account of 2 things: 1 if img has the attribute loading and 2 if the browser is lazyload capable.

viktorix commented 5 years ago

@Lofesa those are good points. I would add 3rd point, set loading attribute for images and other elements if not present.

jmarantz commented 5 years ago

Thanks @Lofesa and @viktorix -- the thought I had on this idea is that we still need the beacon to determine when to add the 'loading' attribute. However if the Beacon says the image is not above-the-fold we should prefer the native mechanism for implementing the lazy-load.

Also AFAICT you still need to enable the loading feature when invoking Chrome by including a command-line option. I do not know if there is a way at this point to detect via (say) user-agent or beacon whether that option is available.

viktorix commented 5 years ago

@jmarantz you can get Chrome version from user-agent:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36

That's a good point about above the fold content. It makes sense to use a beacon to determine which images are above the fold.

Lofesa commented 5 years ago

Hi @jmarantz No, the beacon to "see" if the image is or not above the fold is not needed when the browser can do the lazyload work. As far as I know this, is the browser who decides when the image is loaded. The loading attribute mus be set allways, then if the browser is capable to do the lazyload it decides what images to load and when. So we need to set loading=lazy allways, if not present, and test if the browser is capable or not, if not, we need to do all the work for lazyload the image. Is a similar thing as if the image has data-src, if the image has it we do nothing to lazyload the image as far as we know other lazyload software is present. We can test the browser capability by 2 ways, have a whitelist of UA ( at the moment only chrome version > 76 ) or asking to the browser. The 1st way need to do a maintenance of the whitelist, adding versions and browser that support this feature. The 2snd, way is making a big if in the javascript snipet, if browser is capable or if not. Some like:

if ('loading' in HTMLImageElement.prototype) {
  // supported in browser
} else {
  // fetch polyfill/third-party library
}

If supported in browser we need to copy data-src and data-srcset to src and srcset in all images. If not we need to do all the work that the actual javascript snipet do.

Hope all this is well expressed.

jmarantz commented 5 years ago

I think it's worth testing via webpagetest. But my reasoning is that an above-the-fold image can be loaded very early, while pre-scanning the first flush-window of HTML or via , long before the CSS is loaded that is needed by the browser to execute layout and determine whether the image is above-the-fold.

The value-add of beaconing in mod_pagespeed here is that we can remember in the server whether browsers tend to lay out a particular image above the fold.

If you instruct the browser-to lazy-load all images without beacons, it will defeat the benefit of preloading the important ones. The browser will have to wait until the CSS is loaded before it can determine whether to load the images.

Lofesa commented 5 years ago

Hi @jmarantz Well ... maybe. But why don´t do the same when other lazyload method is present? When data-src is present the pagespeed lazyload do nothing. In the case we determine that a image is in the viewport, we can set the attribute loading = eager that load the image (or iframe) inmediately regardless on where the image is located. In the case of chrome implementation the distance on where the images are pre-loaded changes with the type of connection, for a 2G connection the distance is bigger than for a 4G, so maybe we interfere with these feature.

jmarantz commented 5 years ago

"why don't we [use PageSpeed Beacons] when other lazyload method is present?

It's hard to boil the ocean. PageSpeed's mission is to take a website that is not yet optimized and improve it. It is much harder to take one that is already optimized but with fatal mistakes, such as lazy-loading an above-the-fold images, and fix it.

In contrast, I think it is within the mission to use the best possible option to optimize a page, and I am definitely sold that if Chrome's lazyload method is available, that is superior to building it via JavaScript.

we determine that a image is in the viewport, we can set the attribute loading = eager that load the image (or iframe) immediately

That sounds good.

the distance on where the images are pre-loaded changes with the type of connection, for a 2G connection the distance is bigger than for a 4G, so maybe we interfere with these feature.

How would we interfere with that feature if we integrated the Chrome lazyloading technique when applicable?

Lofesa commented 5 years ago

the distance on where the images are pre-loaded changes with the type of connection, for a 2G connection the distance is bigger than for a 4G, so maybe we interfere with these feature.

How would we interfere with that feature if we integrated the Chrome lazyloading technique when applicable?

I don´t know, cause I have not read the code of the lazyload filter in deep and don´t know what it do step by step. Perhaps an approach can be set loading = lazy in all images until pagespeed can determine if the image is in the viewport and when pagespeed can, change it to loading = eager or only put the loading = lazy attribute when pagespeed put data-pagespeed-lazy-src attribute.

The hard thing is determine if the browser is lazyloader capable, I don´t know other method than javascript. Can c++ do a capability test online? or we need a whitelist of brorser versions?

At the moment all this stuff is very confusing cause chrome 76 can lazyload images and iframes, but is not enabled by default, the user need to enable it manually.

jmarantz commented 5 years ago

Due the fact that it's not on by default I don't think it will affect most users. I would do a version-check in the user-agent for the first version that has it on by default.

Then I would leave the beaconing. But use the user-agent matcher infrastructure to lazyload via the attribute if the browser supports it, otherwise use the javascript impl.

Lofesa commented 5 years ago

More info relevant on this: From Wordpress.org core devs https://core.trac.wordpress.org/ticket/44427

From Gutemberg editor devs https://github.com/WordPress/gutenberg/issues/15753

EDIT: Chrome 77 is released and had lazyload enabled by default, so chrome version => 77