Make WordPress Core

Opened 3 weeks ago

Closed 3 weeks ago

#64823 closed defect (bug) (fixed)

Image in navigation overlay or in viewport-conditional block can get `fetchpriority=high` and degrade LCP metric for page

Reported by: westonruter's profile westonruter Owned by: westonruter's profile westonruter
Milestone: 7.0 Priority: normal
Severity: normal Version: trunk
Component: Media Keywords: has-patch has-unit-tests
Focuses: performance Cc:

Description (last modified by westonruter)

This ticket is a companion to the corresponding Gutenberg#76181 and Gutenberg#76301 issues.

When an IMG is added to the new Navigation Overlay in WP 7.0, it can get misidentified as deserving fetchpriority=high when the actual LCP element IMG is further down it the page.

While the Gutenberg PR addresses this issue by adding fetchpriority=low to such IMG tags, the logic in wp_get_loading_optimization_attributes() needs to be updated to account for such tags so that they do not get lazy-loaded. WHen an image is in the Navigation Overlay or somewhere else that is occluded from view (e.g. a Details block or non-initial carousel slide), it is very important for the IMG to not get lazy-loaded because it means there will be a delay when attempting to view the image since it isn't loaded yet. For the Navigation Overlay, there is no browser heuristic to know it should start to load the image prior to the user clicking on the nav menu button. So the images must be loaded unconditionally, but in a deprioritized way that does not compete with loading resources in the critical rendering path.

For more, see docs on web.dev: https://web.dev/articles/fetch-priority#lower-carousel-priority

Similarly, when a block is displayed conditionally in a viewport with block visibility, it may erroneously get fetchpriority=high even though it is not displayed. This is due to logic in wp_get_loading_optimization_attributes() and wp_maybe_add_fetchpriority_high_attr() and it can be avoided by adding fetchpriority=auto to IMG tags in such blocks. See Gutenberg issue. A further needed improvement is to avoid IMG tags with fetchpriority=auto from contributing to the overall media count so that that don't cause lazy-loading to be added prematurely.

Change History (5)

This ticket was mentioned in PR #11196 on WordPress/wordpress-develop by @westonruter.


3 weeks ago
#1

  • Keywords has-patch has-unit-tests added

Trac ticket: https://core.trac.wordpress.org/ticket/64823

With https://github.com/WordPress/gutenberg/pull/76208 checked out and there are 5 large images added to a Navigation Overlay and 5 large images in the post content, given the following script being run in the console:

Array.from(document.querySelectorAll(".wp-site-blocks img")).map((img) => {
  return {
    insideNavOverlay: !!img.closest(".wp-block-navigation__overlay-container"),
    loading: img.loading,
    fetchPriority: img.fetchPriority,
  };
});

<details><summary>Before ❌</summary>

[
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": false,
        "loading": "lazy",
        "fetchPriority": "auto"
    },
    {
        "insideNavOverlay": false,
        "loading": "lazy",
        "fetchPriority": "auto"
    },
    {
        "insideNavOverlay": false,
        "loading": "lazy",
        "fetchPriority": "auto"
    },
    {
        "insideNavOverlay": false,
        "loading": "lazy",
        "fetchPriority": "auto"
    },
    {
        "insideNavOverlay": false,
        "loading": "lazy",
        "fetchPriority": "auto"
    }
]

</details>

<details><summary>After ✅</summary>

[
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": true,
        "loading": "auto",
        "fetchPriority": "low"
    },
    {
        "insideNavOverlay": false,
        "loading": "auto",
        "fetchPriority": "high"
    },
    {
        "insideNavOverlay": false,
        "loading": "auto",
        "fetchPriority": "auto"
    },
    {
        "insideNavOverlay": false,
        "loading": "auto",
        "fetchPriority": "auto"
    },
    {
        "insideNavOverlay": false,
        "loading": "lazy",
        "fetchPriority": "auto"
    },
    {
        "insideNavOverlay": false,
        "loading": "lazy",
        "fetchPriority": "auto"
    }
]

</details>

The diff shows the changes to the first three images in the content (outside of the navigation overlay):

  • .json

    old new  
    2626    },
    2727    {
    2828        "insideNavOverlay": false,
    29         "loading": "lazy",
    30         "fetchPriority": "auto"
     29        "loading": "auto",
     30        "fetchPriority": "high"
    3131    },
    3232    {
    3333        "insideNavOverlay": false,
    34         "loading": "lazy",
     34        "loading": "auto",
    3535        "fetchPriority": "auto"
    3636    },
    3737    {
    3838        "insideNavOverlay": false,
    39         "loading": "lazy",
     39        "loading": "auto",
    4040        "fetchPriority": "auto"
    4141    },
    4242    {

Fixes:

  1. Preserve fetchpriority=high being assigned to the first large image outside of the Navigation Overlay.
  2. Prevent adding loading=lazy on the first three images in the content.

## Use of AI Tools

None

@westonruter commented on PR #11196:


3 weeks ago
#2

cc @mukeshpanchal27

#3 @westonruter
3 weeks ago

  • Description modified (diff)
  • Summary changed from Image in navigation overlay can get `fetchpriority=high` and degrade LCP metric for page to Image in navigation overlay or in viewport-conditional block can get `fetchpriority=high` and degrade LCP metric for page

@westonruter commented on PR #11196:


3 weeks ago
#4

@mukeshpanchal27 I've expanded the scope here to include the _closely_ related changes for block visibility described in https://github.com/WordPress/gutenberg/issues/76301.

#5 @westonruter
3 weeks ago

  • Resolution set to fixed
  • Status changed from assigned to closed

In 61934:

Media: Add optimization support for IMG tags with fetchpriority=low or fetchpriority=auto.

This updates wp_get_loading_optimization_attributes() and wp_maybe_add_fetchpriority_high_attr() to account for cases where an IMG has fetchpriority=low or fetchpriority=auto:

  • IMG tags with fetchpriority=low are not lazy-loaded since they may be in a Navigation overlay, Details block, or Accordion Item block and need to be loaded the instant the user toggles the block.
  • IMG tags with fetchpriority=auto do not increase the media count since they may be hidden in a viewport by block visibility settings.
  • Blocks with conditional visibility (such as hidden on mobile or desktop) now automatically add fetchpriority="auto" to their contained IMG tags to prevent them from erroneously receiving fetchpriority=high or affecting the lazy-loading of subsequent images.
  • An IMG with fetchpriority=auto which also surpasses the wp_min_priority_img_pixels threshold will prevent a subsequent image from getting fetchpriority=high.

Developed in https://github.com/WordPress/wordpress-develop/pull/11196
Includes backport of Gutenberg#76302.

See related Gutenberg issues:

  • 76181: Image in navigation overlay can get fetchpriority=high and degrade LCP metric for page.
  • 76268: Image in collapsed Details block may erroneously get fetchpriority=high even though hidden.
  • 76301: Block Visibility: IMG in viewport-conditional block may get fetchpriority=high even when not displayed.
  • 76335: Image in collapsed Accordion block may erroneously get fetchpriority=high even though hidden.

Follow-up to r56347, r56037.

Props westonruter, mukesh27, ramonopoly, wildworks.
See #58235.
Fixes #64823.

Note: See TracTickets for help on using tickets.