Participants
- Nic Jansma, Yoav Weiss, Amiya Gupta, Andy Luhrs, Bas Schouten, Dave Hunt, Franco Vieira de Souza, Joon Hur, Leon Brocard, Michal Mocny, Nazim Can Altinova, Justin Link, Noam Helfman, Patrick Meenan, Simon Fraser, Barry Pollard
Admin
- Next meeting: October 9, 2025 (11am ET / 8am PT / 5pm CET)
- Feedback form on WG participation
Minutes
- Simon: Time the image resource is loaded
- ... loadTime is the first time the image is presented
- ... as described I'd expect it to match resource load time as observed in ResourceTiming
- ... But that's not the case according to WPT
- ... Add Img() and load it, but later append to DOM
- ... Not sure what the loadTime should be
- Michal: I think the question is captured well
- ... Haven't 100% audited what Chromium does
- ... loadTime is later of resource load time, or when it was rooter
- ... If you have Prefetch directives or other mechanisms, the response might end before the element becomes rooted and is possible to render
- ... Resource can be loaded before page is ready to render it
- ... LCP sub-parts, this gap became the largest surprising gap
- ... We thought downloads, or discovery was large, but the gap where resource was available but ability to host was not, was largest
- Simon: Gap between RT load time and paint time
- ... Is loadTime that of the first paint?
- Michal: In Chromium, on main thread event loop, we are informed of resource availability and mark loadTime there
- ... But still need to update rendering steps: paint, render, present times
- ... load time may be a few animations earlier but not going to be a lot earlier
- ... Could also hide content, and then later show content
- Simon: Assuming image is loaded, it's DOM mutation time
- Yoav: Is there decoding in there as well
- Michal: Decoding would be there as well
- Simon: Have a subtree with images in it, at the time you root that subtree it's loadTime
- Michal: We need to audit exactly how we do it
- ... PaintTiming for images is keyed off both node and media
- ... If multiple nodes are rooted w/ same media, independent timings
- Simon: Another interesting case
- ... Need some clarification in cases of DOM mutations
- Michal: responseEnd and loadTime not being same is expected and valuable
- Simon: Need WPT for cases where the timing is different
- Yoav: Dave/Bas do you have details on implementation details?
- Bas: I don't know, Justin?
- Justin: I'd have to look to find out
- Yoav: AI for Chrome and Firefox folks to see what implementation is doing, and document that on the issue and then we can make progress on the WPTs
- Simon: Impacts of compositing
- ... and implementor might track when things get painted to trigger LCP
- ... but there are ways moving things around that don't involve painting
- ... might have an element offscreen, but it has a transform/will-change that it's offscreen so it's been painted already
- ... From user perspective there's a big visible change, but LCP doesn't capture that right now
- ... Maybe you have an element that's painted, offscreen, scroll brings into view.
- ... LCP won't track first paint as it's outside viewport, programmatic scroll maybe it's not painted again, just compositor
- ... Another way to implement is to look at paint tree each frame and look for when things are painted, it would capture this
- Michal: Chromium is hooked into paint code, but would still have the issue here
- ... would not be considered a paint candidate
- ... I think Chromium also has some of these flaws
- Bas: I can imagine the same for us (Firefox) but don't know the answer
- Simon: Implementation-specific that some browsers may trigger paints on transforms, others not.
- Michal: I think it would serve developers best to represent as accurately as possible what visitor has seen
- Barry: I think it is an explicit decision to not handle this
- ... First paint onscreen as transform happens before first paint
- ... Chrome doesn't handle this
- Nazim: We're (Firefox) not reporting LCP for will-change property
- Bas: Should this be a WPT then?
- Yoav: Yes
- Michal: Is will-change treated as a composited property?
- Bas: I believe so yes
- ... General question about compostor-driven animations, not just top/left
- ... Causes things that get moved into viewport on compositor
- Yoav: Simon you mentioned walking paint tree on compositor scrolls, is that feasible? From perf/cost perspective
- Simon: I don't think it's feasible
- Michal: If I could straw man, ideal goal of LCP is to best represent the loading experience from the user
- ... Doesn't really matter if it's composited or layout property
- ... Arbitrary
- ... Even more-so would be somewhat randomness of implementation details of what gets recorded
- ... Otherhand, question if it's common for pages to do this thing for UX
- ... How important is it to handle?
- ... If you have a big canvas, and custom paint within canvas, LCP doesn't handle those cases
- Bas: Wonder about if a element is drawn, and largest element not in rendered viewport, we have an artificial viewport, not sure if we could part in window or rendered area
- Simon: Master size clips to viewport
- ... But you only ever count an element once. If it moves and becomes bigger, you don't count again.
- ... Not sure any WPT test the exact rectangles
- Barry: Looking at code-pen it draws offscreen then uses JS to pull onscreen
- ... Anything rendered offscreen is out of scope for LCP
- Michal: I think we have a carveout for initial rendered size is zero then non-zero, we could the non-zero size
- ... Problem is a layout-inducing property, we observe second paint with different location onscreen and different intersected size
- ... transform property that is composited, we don't see that at the right time (to LCP)
- Bas: I wonder what happens if you then later do something that triggers a paint, do we do LCP then?
- Barry: We do it based on element and URL, if src doesn't change, the second paint we don't count, unless you change src
- Bas: If you change top property then there is a LCP generated
- Barry: If you draw "zero" pixel size then move it in, we ignore zero-sized elements
- Michal: Every time we paint an image, we observe that paint and see if we've done accounting for this before, if it's not sufficiently loaded or painted (size zero) we'll keep waiting too
- ... Eventually it'll be sufficiently loaded and painted
- ... Layout property changed, i.e. programmatic scroll, it will be reported and never observed again
- ... Animated it we mark the first pixel, later animations will never be marked
- ... Some other property could change we do have visibility on and it moves into viewport
- ... UX deficiency, known trade-off for implementation viability
- ... If we could solve easily, we would
- Yoav: If there's already interop on not implementing this, fastest path for Simon is to not do this and look at it for later interop
- Simon: I am concerned about differences between implementations, could get different behavior
- Yoav: Yes we should make sure we're aligned
- Bas: I'd be receptive to this being an Interop 2026 things
- Barry: For IFRAMES this registers in Chrome but not Firefox
- ... Yes we should fix it but not be a blocker
- Simon: There are some WPT that cover compositing, but not this
- Barry: We should add as a WPT, but not for Interop 2025
- Bas: For Interop 2026, we'll have paint mix-in
- ... Seems like when we do paint mix-in, we'll need to do things that aren't in Firefox
- Michal: Compositor knows what's on screen
- Yoav: Agree to add WPTs, but not necessarily change current behavior?
- Simon: I'd ask for a note in the spec
- Bas: Agenda for TPAC
- Michal: Does intersection observer fire in cases or not?
- ... May not be aware of it for same reason
- ... Same inconsistencies may exist for that API
- Simon: Recomputes rectangles for things being observed, you've opted into it, more complex
- ... In theory they should be the same
- Simon: No link to algorithm here in the spec
- ... Affects transform, clipping on ancestors
- ... One thing confuses me on PaintTiming
- ... I don't think LCP implementations consult ancestor clipping
- ... I think we need to specify this more closely
- ... Maybe it's the same thing as the intersection observer
- ... If you're allowed to ignore ancestor transforms, you can throw away rectangles
- ... If you need to consult, you don't know scale
- Michal: I think your intuitions are correct there
- ... Might match Chromium
- ... I think you have it right the way you describe it
- ... So we should clarify
- Yoav: Would clarification occur in Intersection Observer, refining algorithms there?
- Simon: If this algorithm is correct it'd be what we'd link to
- Michal: Step 1 here is to get bounding box for target, for text nodes we compute bounding box using a separate algorithm
- ... To get intersection between the root and box
- ... We need to start at step 2 half the time for text nodes, and step 1 for images
- ... Perhaps a small change here
- Yoav: Agree here, it's just work?
- Simon: I think so. Need to add WPTs for ancestor clips
- Simon: Is element's opacity, the property or up the ancestor chain?
- Yoav: Agree it makes sense, not sure if this is what implementations are doing?
- Michal: I tried to understand, it might be similar to transform example
- ... Special carve-out for opacity of body (document element), if content is painted and we mark it's timings but we notice it's not visible opacity<=0, we wait for it to go to a non-0 opacity
- ... If they're nested within other containers, we don't track all of those
- Simon: Opacity could also be just a compository change
- Bas: May be different in Firefox, if opacity=0 and not hit-tested. From absolute-0 to something it could trigger a paint
- Simon: Given frequency for things to hide then reveal, I think it's important to have interop on this one.
- Michal: A/B tests like Optimizely, could re-render and swap. Specific pattern commonly use.
- ... Motivation for narrowly-scoped fix
- ... Some live sites were animating every piece of content, have large LCP values
- Simon: Spec clarification + WPTs needed
- Michal: Wondering if spec notes about differences here would suffice
- ... Or do we need to specify sets of cases with predictable behavior
- Yoav: Useful to discuss this as well at TPAC
- ... Is there a reasonable path to implement this in a performance-reasonable way, then we should probably try to define what that path should look like
- ... Generally try to move in that direction
- Bas: Added to TPAC document as well
- Simon: Ambig about which one it applies to, link should be fixed up
- ... Ancestor transforms?
- Yoav: Quick PR to fix
- Simon: Also falls into compositor thing to some degree
- ... key-frame with opacity:0 then something else at end, browsers may differ on when to paint that content
- ... Differences in Firefox and Chrome already
- Bas: When element renders at opacity:0 or some non-0 capacity?
- Simon: When animation starts, any opacity>0
- Bas: Matches what I thought would happen
- Michal: Not a composited property then?
- Bas: Opacity:0 not hit-tested, doesn't get a display item, when change it needs to go to the main thread to get work
- Michal: Done some complex work
- Bas: Ship display list over to compositor, rather than rendering like Chrome does
- Simon: Triggers LCP when animation start
- ... Firefox triggers it right when it starts
- Bas: Could depend on circumstances
- Michal: Related to a few issues we've talked about today. Bas mentioned rendering viewport, tiles offscreen for scrolling
- ... LCP indirectly doesn't have an issue because we do a viewport intersection
- ... ElementTiming does have this issue in Chromium because we don't have >0 size for elements
- ... Off-viewport rendered, just because they were in rendered viewport
- ... LCP when some content is visible
- ... For ElementTiming, do you report when the first pixel is visible, all content is visible? Unclear
- ... LCP not as affected
- Simon: Chrome is not firing LCP in this case even when element is becoming available
- Michal: We only do special thing if opacity goes from 0 to non-0, then elements are now reported
- ... I could try a version that animations body element
- ... Question is how we observe opacity changes is constrained in Chromium
- ... What do we want? Similar to other cases, in principle, when content becomes available to user, best UX
- ... At the end of the day it's a bit of a heuristic
- Simon: Treat this as a WPT and for Interop 2026?
- Yoav: Makes sense
- Simon: No way to reflect user scroll that ?
- Yoav: Change HTML spec to introduce this concept
- ... We can add a note saying what we have implemented today is not what we need
- ... Long term we want HTML change
- Noam: Idea scroll-input-source that would provide information on what kind of scroll it was, programmatic, mouse, touch
- Yoav: Pointers would be useful, but we should try to not delay this
- Michal: Another complete angle to consider
- ... LCP defers to EventTiming for discrete input
- ... EventTiming doesn't want to measure scrolling, as it gets complicated + compositor driven
- ... Initial gesture that will result in scrolling, that could already be an EventTiming
- ... User-gesture that resulted in a scroll
- ... Could prevent scrolls from starting
- ... If we fix EventTiming for that to be in scope, for first user gesture, could wait for that moment
- ... If you pointer down, wait for pointer cancel or up, may result in dragging or scrolling, if you block pointer down we block scroll from happening
- Yoav: Seems easier to define this new spec concept in HTML, unless they have other thoughts on the matter
- ... Next step is to file an issue or PR on HTML to see what that looks like. If pushback, we need another angle to tackle this
- Barry: For web-virtals, we wanted to measure scrolls, had to clean up event handlers. Would like and easy platform way to measure this
- Yoav: Don't disagree
- ... Alternative is to add a note until the other thing is ready
- Simon: Current spec text caused me to implement incorrectly because it is wrong
- Yoav: Happened to Sean in 2022
- Michal: Does WebKit, Firefox have a way to implement this?
- Simon: Flag of isUserScrolled
- Bas: Yes I think we can distinguish the events
- Barry: I know we don't cleanup the things, but does Chrome just not emit LCP event in that scenario
- Michal: We observe scroll, and know how it was initiated, only a few types we use to stop LCP
- Barry: Chrome would not emit LCP, even if RUM providers won't finalize LCP, Chrome will be "done"
- ... Can we put in spec, browsers have a way of knowing non-programmatic scrolls.
- Bas: I don't think we can without having that spec'd what it means
- Yoav: Can do that as part of HTML, then use that in LCP
- Bas: First need the spec
- Michal: Reason we have this in first place, is user can scroll at arbitrary times and that affects things
- ... However users often scroll early
- ... If we've already added image to DOM, asked to paint, we will measure to completion and still report it
- ... If you observe scroll it may not be the last candidate you see