-
Notifications
You must be signed in to change notification settings - Fork 99
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
Add fetchpriority=low to occluded initial-viewport images #1482
Conversation
…ent_positioned_in_any_initial_viewport() methods to OD_URL_Metrics_Group_Collection
Still can be implemented here:
|
@@ -90,17 +90,43 @@ public function __invoke( OD_Tag_Visitor_Context $context ): bool { | |||
if ( is_null( $element_max_intersection_ratio ) ) { | |||
$processor->set_meta_attribute( 'unknown-tag', true ); // Mostly useful for debugging why an IMG isn't optimized. | |||
} else { | |||
// Otherwise, make sure visible elements omit the loading attribute, and hidden elements include loading=lazy. | |||
// TODO: Take into account whether the element has the computed style of visibility:hidden, in such case it should also get fetchpriority=low. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be addressed later as part of #1587
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
if ( $is_visible && 'lazy' === $loading ) { | ||
$processor->remove_attribute( 'loading' ); | ||
} elseif ( ! $is_visible && 'lazy' !== $loading ) { | ||
if ( true === $context->url_metric_group_collection->is_element_positioned_in_any_initial_viewport( $xpath ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to do a method_exists()
check here because Image Prioritizer here now requires Optimization Detective version 0.7.0+, which is the version this method is introduced in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@westonruter This looks great to me. Only a few minor questions.
/* translators: 1: current aspect ratio, 2: minimum aspect ratio, 3: maximum aspect ratio */ | ||
__( 'Viewport aspect ratio (%1$s) is not in the accepted range of %2$s to %3$s.', 'optimization-detective' ), | ||
/* translators: 1: current aspect ratio, 2: minimum aspect ratio, 3: maximum aspect ratio, 4: viewport width, 5: viewport height */ | ||
__( 'Viewport aspect ratio (%1$s) is not in the accepted range of %2$s to %3$s. Viewport dimensions: %4$sx%5$s', 'optimization-detective' ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it important to include the dimensions in the message here?
Related: Maybe use a single placeholder in the string for WIDTHxHEIGHT
? That portion doesn't need to be translatable individually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not important, but it explains how the aspect ratio was computed.
I've combined the width and height in 38f2e70
plugins/optimization-detective/tests/test-class-od-html-tag-processor.php
Outdated
Show resolved
Hide resolved
// Also prevent the image from being lazy-loaded (or eager-loaded) since it may be revealed at any | ||
// time without the browser having any signal (e.g. user scrolling toward it) to start downloading. | ||
$processor->remove_attribute( 'loading' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure this is needed? If I remember correctly, browser's lazy-loading implementations support horizontally offset images too, so shouldn't those still be lazy-loaded where applicable?
Worth noting that we may need to differentiate between "this is hidden by being offset outside the viewport" vs "this is simply hidden but technically would be in the viewport if shown".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case, fetchpriority=low
is what is recommended as opposed to loading=lazy
as per Optimize resource loading with the Fetch Priority API:
And per Optimize Largest Contentful Paint:
In the case of a carousel I believe you are right now that loading=lazy
may be OK, since the user can scroll as a signal to the browser that the image should start getting downloaded before displayed. However, the other case I have in mind are images which are hidden as being part of a mega menu, in which case they may be shown immediately in response to a user hovering over a nav menu item. In this scenario, loading=lazy
would mean the image is not loaded when when the element is displayed. So I think fetchpriority=low
is safer. Also, a carousel may not involve scrolling at all. The slides may be programmatically changed, so again there wouldn't be a user signal to start loading the image before the element is displayed.
… add/fetchpriority-low
… add/fetchpriority-low
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @westonruter!
This is a follow-up PR (sub-PR) to #1373 which is branched off of
add/embed-optimizer-min-height-reservation
.Fixes #1309.
When an image is in the initial viewport (i.e. its
boundingClientRect.top
is less thanwindow.innerHeight
) and yet itsintersectionRatio
is0.0
, at present such images are gettingloading=lazy
incorrectly. Such images are likely part of subsequent carousel slides and gettingloading=lazy
could result in them not being loaded by the time the carousel slide is displayed. Acccording to the Web.dev article on fetch priority, such images should actually getfetchpriority=low
. This is what is implemented by this PR. In particular, see #1309 (comment) where this PR implements these points:It does not implement the following point, which will come in a subsequent PR (to address #1587):
Two new methods are introduced which determine whether an element or elements are positioned in the initial viewport (that is, they are not below the initial viewport):
OD_URL_Metric_Group_Collection::get_all_elements_positioned_in_any_initial_viewport()
OD_URL_Metric_Group_Collection::is_element_positioned_in_any_initial_viewport()
Carousel Example
Given the Ultimate Blocks plugin's Carousel block with markup as follows, with simply 3 images added as carousel slides:
Block Markup
With this Carousel being the only block in a post where the initial slide's image is the LCP element:
The Prettier-formatted rendered markup is as follows without the changes in this PR:
Notice in particular that Ultimate Blocks does not add
width
andheight
attributes to the images in the carousel, so WordPress core's server-side heuristics does not addfetchpriority=high
to the initial image. Additionally, note the priorities of these images in the DevTools network log:All three images have an initial priority of medium and the third carousel image is then elevated by Chrome to a high priority even though it is not even displayed (and it is not the LCP element).
Compare this with when the changes in this PR are applied and URL Metrics have been gathered. In the network log, now the LCP image element now has an initial and final priority of high and the subsequent slides both have initial/final priorities of low.
The Prettier-formatted rendered markup is as follows:
Note the inclusion of
fetchpriority=high
on the initial carousel slideimg
andfetchpriority=low
on the subsequent ones.