Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Responsive LCP image penalized for lazy-loading by lcp-lazy-loaded audit #16034

Open
3 tasks done
westonruter opened this issue Jun 4, 2024 · 3 comments
Open
3 tasks done
Assignees

Comments

@westonruter
Copy link

FAQ

URL

https://comparing-lcp-images-with-lazy-loading-and-fetchpriority-high.glitch.me/lazy-loaded-lcp-image-with-fetchpriority-high-preload-link.html

What happened?

Consider a page which shows a different image depending on whether it is a desktop or mobile device. In order to prevent both images from being loaded on both device form factors, it is necessary to add loading=lazy to the images:

<img id="vertical"   src="https://cdn.glitch.global/6482ece1-578b-4f64-93e8-c1edca8e14d8/bison-vertical.jpg?v=1717451469904" alt="🦬" width="1426" height="1761" loading="lazy">
<img id="horizontal" src="https://cdn.glitch.global/6482ece1-578b-4f64-93e8-c1edca8e14d8/bison-horizontal.jpg?v=1717451240067" alt="🦬" width="2700" height="1761" loading="lazy">

Nevertheless, since these are LCP images for their respective viewport sizes, they also must be loaded with fetchpriority=high which can be achieved with preload links that include media queries:

<link rel="preload" as="image" href="https://cdn.glitch.global/6482ece1-578b-4f64-93e8-c1edca8e14d8/bison-vertical.jpg?v=1717451469904"   fetchpriority="high" media="screen and (orientation: portrait)">
<link rel="preload" as="image" href="https://cdn.glitch.global/6482ece1-578b-4f64-93e8-c1edca8e14d8/bison-horizontal.jpg?v=1717451240067" fetchpriority="high" media="screen and (orientation: landscape)">

Nevertheless, the lcp-lazy-loaded audit is failing for such a page (PSI):

image

This is in spite of the fact that such images load comparably fast to img tags with fetchpriority=high:

Test Case LCP-TTFB
Plain LCP image 139.9 ms
Lazy-loaded LCP image 159.4 ms
Lazy-loaded LCP image with fetchpriority=high attribute 150.4 ms
LCP image with fetchpriority=high attribute 124.5 ms
LCP image with fetchpriority=high preload link 126.5 ms
Lazy-loaded LCP image with fetchpriority=high preload link 129.0 ms

The LCP-TTFB metric comes from the benchmark-web-vitals command in the GoogleChromeLabs/wpp-analysis repo. It reflects the LCP time subtracting the TTFB. The value is the median over 25 requests using the following command:

npm run research -- benchmark-web-vitals -n 25 -f urls.txt -o csv -m LCP-TTFB

For more info, see the Glitch.

What did you expect?

The lcp-lazy-loaded should not have failed.

What have you tried?

I suggest that the following code in the audit be modified:

const wasLazyLoaded = lcpElementImage.loading === 'lazy';

Given the LCP image's src and srcset it should also check if there is a preload link with fetchpriority=high which has the corresponding href and imagesrcset attribute values. If so, then wasLazyLoaded should be considered false.

How were you running Lighthouse?

PageSpeed Insights, Chrome DevTools

Lighthouse Version

12.0.0

Chrome Version

No response

Node Version

No response

OS

No response

Relevant log output

No response

@adamraine
Copy link
Member

Is there any reason you can't use <picture> instead? Even though the image loading doesn't appear to be affected by loading=lazy in this case, I don't see why you need to use it other than to select a specific img src which is a feature that is better provided by <picture> IMO.

@westonruter
Copy link
Author

Using a picture element would be an alternative, yes, but it wouldn't always be an option. Not all platforms support generating picture elements, and the different image in question may be located in separate DOM trees. Consider a page which has two separate headers, one for mobile and one for desktop, within each there is a separate img specific to mobile and desktop respectively. A picture element wouldn't work in this case.

My interest here is specifically in the context of developing optimizations on top of WordPress Core. I'm working to take the existing markup generated by the theme and prioritize the loading of the LCP image based on the current viewport. WordPress doesn't support picture yet. My concern is that if the optimization adds loading=lazy to the LCP image while also adds responsive fetchpriority=high preload links, Lighthouse will flag this as an error even though in reality the performance is improved. So a user testing their site in Lighthouse will think the optimization (WordPress/performance#1270) is making things worse.

@adamraine
Copy link
Member

I think you could still get picture to work by using two picture elements and loading a "null" data URI image for the viewport size that isn't applicable. That being said this approach is equally hacky if not more hacky compared to the lazy loading approach and you also mentioned how picture may not be available in all cases.

I think we will adopt your suggestion of allowing images with loading=lazy if they have a link preload tag with fetchpriority=high

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants