Participants
Ishan Anand, Ben De kosnik, Nicolás, Annie, Michelle, Noam H, Michal, Giacomi, Gilles, Carine, Nic, Yoav
Minutes
- Annie: Layout instability is not changing
- … We have a metric called cumulative Layout Shift
- … Concerns about the fact it grows unbounded, causing frustration
- … Tried 200 strategies to improve that
- One of the a sliding window, that’s updating over time
- … session window which is grouping layout shifts and stops when there’s a gap
- … Gap of a second was best
- … Looking at the max window, both by summing and averaging them
- … Performed well in initial tests
- … Implemented and tried it out
- … All strategies reduced correlation with time spent, which is good
- … Accomplishing goals
- … Found that 300ms window was too short to capture related layout shifts
- … So was looking for max over session window and max over sliding window
- … Would it make sense to rename the metric?
- … Thoughts on different strategies?
- Benjamin: Can you clarify the 5 seconds limit? Is there specific content that goes over?
- Annie: infinite scroller that janks on each scroll - that can create small shifts that go over 5 seconds
- Michal: Other common examples are layout inducing animations, or interval driven page updates
- Annie: We saw poorly animated “scores” popping in, which over times those scores popping in aren’t getting worse.
- Nic: For the session window, the layout shifts in the window would be summed? How will you aggregate?
- Annie: Max
- Nic: So the worst experience
- Annie: When we looked at statistics, the 75th percentile or median experience, ti’s hard for the developer to reason about
- … Only high percentiles correlated with bad user experience, and describing the interpolation would be confusing
- Nic: Similar to the sliding window, you’re finding the worst 1 second? Easy to reason about
- Michal: Rare situations where a large sliding window would capture the global maximum, but how timings are setup, session would always do the same. Sessions have a variable amount of time. Is a fixed slice important or not? That’s the semantic difference
- Nic: Better browser supports that group user experience or action, you could group these by UX
- Ishan: Read the blog post with a lot of interest. A lot of customers are e-commerce. Interested in the flow eCommerce
- … Going back and forth can be fast in SPA
- … Prefer session windows. Concern that if users go between pages quickly, you can group unrelated CLS. So don’t like uncapped windows.
- … Concerned about users leaving the window open for a long time. Especially if there’s background work.
- … and the last thing, wasn’t clear if the layout shift would be attributed to the URL of the initial page or to the URL of the SPA nav
- Annie: Initial URL
- Ishan: Logically scrolled through multiple pages, but we keep extending the sense of session
- Michal: One way would be to adjust the gap to of the session window to be the same size as the hadRecentInput threshold
- Benjamin: I think that what you’re proposing is different from CLS so would appreciate a new name. Feels different.
- Nic: A lot of different types of tools and services reporting CLS. Agree that it feels different enough that it would make sense to rename
- Yoav: We want to align metrics with user-experience, including BFCache navigation
- … Fire new entries rather than override old entries
- … Single time origin for all navigation
- … Fire new NavigationTiming entries (with new type)
- … Should be web compatible to do so
- .... Also fire new PaintTiming entries
- … How do we correlate those PT with NT entries?
- … Had previously suggested we use .time, but Ryosuke suggested this would be sufficient (for overlapping navigations)
- … New NavigationID on PerformanceEntry
- … Will incrementally increase each new navigation the document goes through
- … Work well for BFCache now, as well as other types in the future (soft navigation), would work well with proposed App History API
- … Spec changes: navigationID to PerformanceEntry, and counter to Document initialized to 0
- … Increment on BFCache navigation
- … Simply initialize navigationID to document
- … (example using PerformanceTimeline)
- … Does this make general sense?
- Noam: Navigation would be an increasing number, and not also surface the type?
- Yoav: The ID would be treated as a pointer to the NavigationTiming entry
- Benjamin: Good way to disambiguate, could be used for Soft Navs
- … Curious about backwards compatibility
- Yoav: NavigationID without BFCache navs would be just 0 all the time.
- … Don’t think content is looking at random properties and if it finds them, it breaks.
- … Are you suggesting forward-compatibility issues I’m missing?
- Benjamin: Maybe it’s just an education thing and telling people what the numbers are
- Nic: We’re not using PerformanceTimeline as much, but the example itself using it, maybe there are some cases where people want to get things by navigation ID
- … For a really long running page like Gmail you want to get things by ID
- Yoav: For an SPA I was thinking you’d have a PO and the callback could choose to segregate by ID
- … RE: Do we want a getEntriesByID() -- this is a pattern from before we had filters, don’t see we need to add a dedicated API
- Noam: We may want the ability to clear the previous entries
- Yoav: Problem with shared buffers (like ResourceTiming) is that when multiple third parties are involved they can stomp on each other
- … PO allows you to register when you want things and unregister when you don’t
- Nicolás: There may be more memory used filtering in JavaScript than what the browser could do
- Yoav: Looking at the internal Chrome implementation I don’t think it’d be that more efficient, for getEntriesByName() it’s not significantly different from getting all and filtering in JavaScript. But we can discuss
- Nicolás: For the observer pattern, would you want to limit to a specific navigationID?
- … i.e. if you want to listen after a BFCache nav and use buffered:true and only get the current BFCache navigation
- Yoav: Maybe worthwhile to wait until we have people who use it in the field
- Noam: Instead of the getEntries() API, could we expose it as a map of .navigations[n]
- Yoav: With performance.getEntriesByType(“navigation”), you could then index
- … Oh but if you want to get all entries based on that ID
- Noam: API would be a direct lookup on that
- Yoav: I’d like to wait until we have implementation experience and see what’s the best way to split
- Nic: I do like this, navigationID is forward looking and could be used for SPA navigation in the future
- Michal: Speaking of forward looking, fundamentally this is about segmenting perf entries based on their logical grouping. In the past, Benjamin talked about slicing based on visibility or whatever
- Nicolás: I’m not sure we want to be able to segment based on everything
- Michal: Got it, so everything needs a navigationID but not everything needs those other attribution
- Yoav: I suspect some of this would be filtering done on the server or in the client anyway
- … Worry about lots of custom filtering machinery when we already have JavaScript that can do the slicing and dicing
- Nicolás: The question is do we want to expose a new FCP when you first become visible.
- Michal: I don’t know if we’d ever expose paint. But for LayoutShifts I’d be interested in knowing if there was a long idle period.
- Yoav: VisibilityObservers will give you better ways of getting that information retroactively
- Michal: Navigation entries give you the ability to slice the data. By that argument, this is a convenience thing. It is future proof.
- Yoav: If we were to consider in the future background and forwarding is a new thing, we could consider resetting the ID in those cases
- … AI: Suggested next steps: Create various PRs on specs related to that (PerformanceTimeline, HTML, PaintTiming at least). Send them over to the list for greater scrutiny.
- … Bikeshedding on the PerformanceTimeline PR if interested.
- Benjamin: If we have monotonically increasing IDs, isn’t the largest the one that could be visible and if it’s not the largest it’s definitely not visible?
- Yoav: Users could theoretically click on the back button then switch to a new tab. This whole BFCache navigation could be invisible for most of its time.
- … Missing concrete examples of what we’d want to expose in those visibility sessions. Agree in principal it’s an interesting idea to explore, but I’m not sure what to do with it right now.
- Benjamin: That’s fine, anything we can do to improve clarification on visibility would be worthwhile. Like the fact it might be able to discard a whole bunch of “what is visible”, and if we could get that as a bonus let’s take it
- Yoav: Right now for ElementTiming we expose loadTime
- … And renderTime for image, for all of the bytes of the image when rendered
- … JPEG-XL folks who are finalizing a format that is progressive would like to expose more than the final time, since it doesn’t show JPEG-XL images show something to the user earlier compared to other formats like AVIF
- … Jon is suggesting having multiple stages where we don’t only expose final render time but also the dimensions, placeholder paint/blur hash, preview paint, “good enough”, then final image
- … Suggesting adding that to ElementTiming
- … From my perspective, it’s interesting information but not sure what people would do with that
- Noam: For evaluating how long it takes for someone to see a gesture, especially on slower connections
- Nicolás: Is the image actually loading before the spinner
- Yoav: What is this defined for animations, is it the first frame?
- Nicolás: I don’t think we do a great job for animations
- Noam: If it an app that has multiple thumbnails and then it shows the full image somewhere, it may not have the high-resolution image in memory yet
- Yoav: But in those cases the thumbnail would be a separate image, and when you clicked it would open the full image
- Nicolás: I think this would only be for progressive images
- Patrick: There’s a weird line where baseline images also draw incrementally
- … Separating incremental painting for baseline images from progressive images
- … Almost want an event where the entire area is updated
- … But I could see, there’s a few companies where they use regular JPEG with custom scans, and the first image is a greyscale and add the color afterwards.
- … In those cases they’d want to know when each scan completes
- Yoav: Instead of multiple defined entries, these are all the times when scans happened
- Michelle: I’m from Pinterest, we have a custom metric called PinToWaitTime and includes load and rendering time of all images in viewport -- has 60% quality of progressive jpegs. We just want to identify a point where our quality threshold has been met
- Nicolás: So we’d need to expose for each scan the quality?
- Patrick: I’m not sure, just the number of scans and that’s up to whose serving the image
- Nicolás: I’m not sure if every browser will paint the same amount
- Patrick: If you do a percentage based on the number of scans or quality
- Yoav: Or number of bits?
- Patrick: I don’t think number of bits will tell you
- Yoav: Giacomo on chat says this could be useful for LCP
- … I think LCP’s semantics are aligned more with “good enough” paint
- ... One of the goals is to be a single number rather than an array of scan
- … Separate issue related to LCP where we converged on “good enough” for its semantics
- Benjamin: Isn’t this an extended version of PaintTiming applied per-element
- … First Paint is placeholder paint, etc
- Yoav: You’re saying there are parallels between those milestones and the full-page render
- Yoav: Asking for use-cases to comment on the issue, stating how they’d use this. Patrick maybe you want to have a more flexible structure related to scans?