Skip to content

Reduce cumulative layout shift (CLS) by attempting to determine heights of embeds beforehand #4729

@westonruter

Description

@westonruter

Feature description

Cumulative Layout Shift (CLS) is a huge detriment to user experience on the web. It is also a huge challenge to solve in the case of 3rd-party embeds. For some AMP components, in particular amp-iframe and amp-list, elements that need to resize based on their contents need to provide an overflow button that needs to be clicked by the user to trigger the element to grow in height if the element is currently in or above the current viewport. The presence of this overflow button can be annoying for users and so it's important the initial height be set to be as close as possible to where the element will be once loaded so that, in the best case, no overflow button needs to be presented.

Nevertheless, for pragmatic reasons, other components do not have such overflow logic and they will resize to fit their contents regardless of being in the current viewport or above. For example, amp-gist:

<amp-gist data-gistid="0769f147e021e0ebfcb04a084987483a" layout="fixed-height" height="10"></amp-gist>
<p>Super interesting information!</p>

When the page loads at first, the user will see “Super interesting information!” momentarily until the Gist loads. This is a gross instance of CLS. The docs for the component call this out in the description for height:

data-gistid (required) The ID of the gist to embed. layout (required) Currently only supports fixed-height. height (required) The initial height of the gist or gist file in pixels. Note: You should obtain the height of the gist by inspecting it with your browser (e.g., Chrome Developer Tools). Once the Gist loads the contained iframe will resize to fit so that its contents will fit. data-file (optional) If specified, display only one file in a gist.

Similar guidance is provided for amp-twitter:

Twitter does not currently provide an API that yields fixed aspect ratio for embedded Tweets or Moments. Currently, AMP automatically proportionally scales the Tweet or Moment to fit the provided size, but this may yield less than ideal appearance. You might need to manually tweak the provided width and height. Also, you can use the media attribute to select the aspect ratio based on the screen width.

This issue, however, is not unique to Gists and Tweets, but it's also an issue for other embeds. For example, embedding Facebook posts also have this issue and the amp-facebook component lacks that same guidance.

All this being said, we should automatically provide the best approximate height for these components as much as possible.

One way this could be done, specifically in the block editor, is to render the component and then scrape the resulting height and then inject that as the height of the embed. This couldn't be done currently with the PHP Optimizer since we need a browser context to load the page, but perhaps the Node Optimizer could add Puppeteer as a dependency to obtain initial heights.

This would essentially be an augmentation of SSR.


Do not alter or remove anything below. The following sections will be managed by moderators only.

Acceptance criteria

  • After having added an Embed block to a post, saving and viewing the AMP page should should require any layout shifting for the block on the frontend.
  • Bonus: Also set the height of embeds on non-AMP pages.

Implementation brief

  1. Check the initial post content for any embeds that lack heights, and watch for insertions or updates to Embed blocks.
  2. Once the Embed block clears its loading state, measure the height and add as a custom block attribute.
  3. Add a render_block filter that passes along the height block attribute to be inserted as a data-amp-embed-height HTML attribute on the figure wrapper element.
  4. Add toAMP_Embed_Sanitizer::sanitize() logic which finds all //figure[ @data-amp-embed-height ] and then copies the value to the ./div[ contains( @class, 'wp-block-embed__wrapper' ) ]/*[starts-with(name(), 'amp-')].

QA testing instructions

Demo

Changelog entry

Metadata

Metadata

Assignees

No one assigned

    Labels

    BentoEditorOptimizerP2Low priorityWS:PerfWork stream for Metrics, Performance and Optimizer

    Type

    No type

    Projects

    Status

    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions