-
Notifications
You must be signed in to change notification settings - Fork 383
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
Reduce cumulative layout shift (CLS) by attempting to determine heights of embeds beforehand #4729
Comments
For some of these, we might still be able to calculate a close approximate height on the serverside based on the content from the embed, but it would mean supporting adding per-embed logic to do so. For example, for a gist, you'll probably get very close by counting the number of lines and then calculating something like To get the number of lines and the line height, you'd fetch the embed content from the server and parse the return HTML. Given that there is direct support in AMP for something lie a gist via its specific component, I don't think it's necessarily bad to mirror that custom support in the Optimizer, and have a few lines of custom logic per component to calculate its height on the server-side. |
Obtaining the dimensions of embedded content is going to be increasingly important as part of the Bento effort because components like While it is possible to approximate the height of embeds server-side, this would indeed need to be done uniquely for each embed. And then it would have to be maintained for each embed. I actually had to do this for the Pinterest embed in Jetpack via Automattic/jetpack#17086, since at the time The code involves a lot of magic numbers: https://github.com/Automattic/jetpack/blob/36151c453f478f613204768725e236be8bd7949a/projects/plugins/jetpack/extensions/blocks/pinterest/pinterest.php#L70-L210 I think it will be much more scalable to do this client-side in the editor. When an embed is rendered, we can store the height as a custom block attribute which we then utilize to supply the height when rendering (either in an embed handler or embed sanitizer). |
Added AC and IB. |
The downside to the client-side approach is that any existing embeds will not have sizes supplied. To supply the initial heights, a site owner would have to touch it: open the post in the editor and re-save once the embeds have loaded. In order to supply the heights for all previous embeds in an automated way, this would involve having some UI that programmatically opens each post one-by-one in an editor and saves if they enter a dirty state. Something similar in concept is the Convert to Blocks plugin, but it doesn't do batch updating of all posts. It still requires opening posts one-by-one. Batch supplying heights retroactively to older posts is out of scope for this issue, but it's something interesting to consider for the future. |
It seems we may need to check responsive breakpoints to determine the heights of the embeds. Adding a tweet I can see that on mobile it is ~500px high but on tablet/desktop it is 630px high: responsive-embeds.mov
That complicates things a bit. Do we capture just the mobile dimensions? Or do we capture mobile, tablet, and desktop and store them all with the embed's block attributes? But when we render the <amp-twitter class="mobile" width="auto" height="500" layout="fixed-height" data-tweetid="1405578489554743296" media="(max-width: 360px)"></amp-twitter>
<amp-twitter class="desktop" width="auto" height="630" layout="fixed-height" data-tweetid="1405578489554743296" media="(min-width: 361px)"></amp-twitter> That doesn't seem ideal. |
Instead of using the |
Nevermind, there's no layout that would fit our needs and allow us to not specify the |
I did some work on a standalone app to help determine initial heights to reduce layout shift a year ago: https://googlechromelabs.github.io/layout-shift-terminator/ For more see: https://web.dev/embed-best-practices/ Granted, the functionality would be much improved with container queries live, but they're almost ready: https://caniuse.com/?search=container%20queries So we could code specifically for them with the necessary browser flags enabled to test them. |
This could be contributed eventually to the WordPress Performance plugin as well. See WordPress/performance#117 (comment) and GoogleChromeLabs/layout-shift-terminator#5. |
@westonruter I performed some research on the above-mentioned scenarios and here are the findings.
See these lighthouse result:
|
Are you saying this will cause jank in the editor? For the Facebook Video embed, I'm seeing two long tasks for HTML parsing and FB script execution: This would particularly be annoying if the sizing is done after insertion while the user is still typing. I guess a way around it would be to wait to do the sizing until the post-publish step. But that would require the user to wait a minute before publishing, which would be annoying. Lastly, I wonder if there is anything that can be done with out-of-process iframes. From reading https://stackoverflow.com/q/11510483/93579 it seems that an iframe that gets
I'm not sure I understand. Could you add a |
For this, I am further investigating the use cases with iframe sandboxing as you suggested above. But furthermore, we will need to benchmark such scenarios which can affect editor performance.
I have added |
I'm not sure what you mean here. Could you elaborate? |
By the above statement I mean the lighthouse is still showing CLS even though I have provided element height by using Layout Shift Terminator. |
@westonruter I have created a POC to demonstrate the possibilities of terminating CLS by measuring dimensions in an iframe. But instead of handling this automatically, I have provided a custom setting, and I will explore more approaches to make this process automatic. You can find the plugin here - https://github.com/rtCamp/wp-cls-terminator. Please note I have temporarily added only a few breakpoints, which can be updated later. |
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
andamp-list
, elements that need to resize based on their contents need to provide anoverflow
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 initialheight
be set to be as close as possible to where the element will be once loaded so that, in the best case, nooverflow
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
: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
:Similar guidance is provided for
amp-twitter
: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
Implementation brief
height
and add as a custom block attribute.render_block
filter that passes along theheight
block attribute to be inserted as adata-amp-embed-height
HTML attribute on thefigure
wrapper element.AMP_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
The text was updated successfully, but these errors were encountered: