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

Support Element Timing on Containers #79

Open
andydavies opened this issue Dec 12, 2023 · 4 comments
Open

Support Element Timing on Containers #79

andydavies opened this issue Dec 12, 2023 · 4 comments

Comments

@andydavies
Copy link

andydavies commented Dec 12, 2023

Currently Element Timing only supports a small number of elements – image, text elements etc.

Developers increasingly think in terms of components, some of these may be a more complex elements e.g table, SVG, MathML, others may be collections on elements within a container – consent popup, product card, menus etc.

Timing these as a whole is an important use case but the closest we can get to that is timing individual elements and then choosing the last timestamp (within a container there's elements that might not be able to be timed)

Ideally developers should able to add the elementtiming attribute to a container element and have the timestamp report when all the children have rendered.

This topic was discussed at the WebPerf Working Group on Dec 7th 2023

Slides from Jason and Andy's introduction: https://docs.google.com/presentation/d/1hX4okVFUpBnlvpHDkP117KBrOcqnFrw-FJR2eMNxxzc/edit?usp=sharing

Recording: https://youtu.be/MjGVtshDN7U

Minutes: https://w3c.github.io/web-performance/meetings/2023/2023-12-07/index.html

@mmocny
Copy link

mmocny commented Jan 15, 2024

Hey Andy, I thought the conversation in Web Perf meeting was fantastic and I believe there were a few good concrete ideas that came out of that.

I'd love to see a summary of all the notes as a concrete set of possible improvements.

@mmocny
Copy link

mmocny commented Jan 31, 2024

Let me take a stab at some summary that I heard:

  • Desire to have element-timing work at a "component" or "container" level, since that is typically the level of UI that developers operate in.
  • Certain elements aren't really supported as they are inherently containers: <table>, , `, etc.
  • We already do this (somewhat) for text-content, where we aggregate distinct text paints in container elements.
  • Some discussion about <table> with empty cells, dynamic content, streaming... when should we consider a container as fully rendered? Which paint if there is a stream of paints?)
  • Should element-timing support reporting multiple paints for the same element? If the contents of the container change over time...
  • What about animations? Should we make a distinction between animation start/end (especially for fade)

Beyond element-timing, LCP algorithm should consider certain types of containers as candidate elements by default (i.e. table of small cells example)


Since our last group discussion a few of us had a separate breakout to discuss some options for next steps.

We realized that element-timing for containers could likely be mostly polyfilled, at least as a first step. Then, we would be better informed about what the defaults should be, and understand better where the real gaps are.

We may still want to add this capability to the platform, it may be to improve DX/performance, or so it could be used by the LCP algorithm by default.


So, how might we try a polyfill, and which Element-timing changes would be useful/needed?

  • Today you need a unique id for each node.
    • This is just an inconvenience and a polyfill could generate unique ids for all child nodes.
  • You need to track the full set of children waiting for paint, and match them up with element timing observer calls.
    • This is also just an inconvenience that a polyfill count do.
  • Element timing fires exactly once, after first paint. For this reason, the element-timing attribute must be supplied as content is added to dom (either parsed from HTML or dynamically inserted).
    • This makes it harder to polyfill as a library onto pre-rendered HTML or onto client-rendered content-- but perhaps is still possible with MutationObservers.
    • Should element-timing support "lazily" asking if a given Node has already been painted?
    • Since it triggers only once, perhaps a Promise-api, where the resolved value is sticky, could work?
  • Element timing will not trigger for content that skips paint, and it may be difficult for a polyfill to differentiate cases when a child hasn't fired Element Timing-- was this because the element is still not painted, or because it isn't going to get painted?

Anything else?

@jasonwilliams
Copy link

jasonwilliams commented Feb 1, 2024

Hi Michal

I think you've summarized it quite well and mentioned most of the points we have discussed.
The overarching goal here is to have elemnt-timing work at a "component" or "container" level, there are many cases to consider in making this work.

Certain elements aren't really supported as they are inherently containers: <table>, , , etc.

Yep, there may be a "quick win" today with some compound elements such as <table> or <svg> where we can already identify it as a container and treat it as a single rendered component, this improves LCP measuring today.
I have a feeling though that due to the nature of modern front-end development, the more common path will be developers needing to signal a container (div) being a component via some attribute (or the framework does it for them). With Web-Components being used in the front-end space too I would be interested to know how this will work with Shadow Dom components.

Should element-timing support reporting multiple paints for the same element? If the contents of the container change over time...

We (Bloomberg) do stream data into our components, for example: numbers being streamed into a grid. We are interested when this grid has been populated, but not when numbers or values have changed. I guess this can become complicated because I would see this as 2 paints:

  1. the div has been rendered (but its empty)
  2. the div now has some content inside (a numeric value) <-- Mark as painted

In our case we care about the later, but the browser wouldn't be aware there is more content coming so this isn't as straight forward and may need more discussion. One idea is to have the candidate model instead of a single-fire (similar to LCP), and once there is interaction on the page we stop checking for candidates and report a final event.

What about animations? Should we make a distinction between animation start/end (especially for fade)

@andydavies has been dealing with this area and he can certainly provide some insights to this.

Polyfill

We're happy to help contribute to a polyfill or at least get the ball rolling.
As you've already pointed out there will be limitations on what we can do in user-land compared to natively in the browser.

Element timing will not trigger for content that skips paint, and it may be difficult for a polyfill to differentiate cases when a child hasn't fired Element Timing-- was this because the element is still not painted, or because it isn't going to get painted?

This is a good point and not one that I've thought about, I guess if some elements are layered visually behind another, the browser wouldn't deem them paintable but the polyfill wouldn't know that so this would have some corner cases. I assume it's not enough to just calculate overlapping elements and there may be other reasons paint is skipped?

Should element-timing support "lazily" asking if a given Node has already been painted?

Yes I think so, frameworks like next.js/server side react will have pre-rendered content from the server side shown in the browser, then it will fire any useEffects after. This means we're bound to see usage of element-timing where the DOM node has already been painted and we just need to "check" that has happened.

@jasonwilliams
Copy link

Here is a link to a prototype:
https://jasonwilliams.github.io/container-timing/

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

No branches or pull requests

3 participants