Participants
Pat Meenan, Yoav Weiss, Nic Jansma, Tom McKee, Noam Helfman, John Engebretson, Steve Kobes, Michal Mocny, Alex Christensen, Ian Clelland, Carine Bournez, Annie Sullivan, Corentin Pescheloche, Dan Shappir, Katie Sylor-Miller, Timo Tijhof, Steven Bougon
Admin
- Next meeting: Feb 3rd 10am PST / 1pm EST
- Yoav: Calls for Consensus from TPAC
- … LCP: 10 thumbs up, no objections
- … Event Timing: 8 thumbs up, no objections
- … Can go ahead with adopting these two incubations into Working Group
Minutes
- Tom: For ResourceTiming, you can query underlying transport mechanism in nextHopProtocol
- … Had an issue in spec where we had a special case to expose this information for cross-origin resources.
- … Change is now to unify the protection, bring nextHopProtocol inline with other sensitive attributes for ResourceTiming
- … Web-visible changes where resources that would have this information before, will have empty string now
- … In Canary in Chrome
- … Seeing if there are any questions or concerns
- Alex: Webkit has also made the change
Summary:
- The most computationally subtle part of CLS is the area of the impact region
- Impact region is a set of overlapping rects: the old and new visual representations of all shifted elements, observed during paint
- Chromium uses an N log N algorithm (N = # of rects) based on a sweep line and a segment tree, details in layout_shift_region.cc
Minutes:
- Steve: Involved in implementation of CLS in Chromium
- … People were interested in algorithm and performance optimizations we made
- … Hooked into rendering pipeline to know when an element has shifted
- … Notifies Layout Shift tracker
- … When done painting we have this list of rects
- … CLS has to calculate a score, hard part is to calculate the area of the union of those rects
- … First attempt was n^2 in number of rects, showed up in our perf alerts
- … Pages with lots of elements moving around are measurably slower
- … First tried a snapped grid, sacrificed precision and might’ve caused a way for browsers to diverge
- … In spec the browser can make these tradeoffs
- … New way is to make a data structure called a segment tree
- … Balanced binary tree, where nodes are intervals between those points
- … Sweep line from left to right and we are seeing which parts of line are overlapping region
- … Time cost for N rects is logN for updates, so N*logN
- … Other update is move distance, so we just pay attention to the largest move we see
- … Interesting bits in code are in layout_shift_region.cc
- … Don’t think there’s anything inherent in spec or platform that makes this computationally challenging
- Benjamin: Thanks for the knowledge sharing, will need time to review
- Steve: Will share slides
- Yoav: Are details here enough for you to pull string, or is there anything else that folks on Chromium side to help implement
- Benjamin: Good first step, let us come back to you at implementation phase
Summary:
- CLS is an accumulation of unexpected layout shifts, which means that shifts which follow user input should be ignored.
- But there are other layout-inducing actions which are the result of direct user input with the browser itself, not the web contents: zooming, translating, resizing, find-in-page, back/forward buttons, visibility changes, etc.
- Implementers should consider these as input exclusion events and reset the 500ms timer when they happen.
- Some good discussion around how 500ms around back/forward is necessary, but not sufficient to solve the SPA CLS attribution issues, as well as spec change questions.
Minutes:
- Michal: When we explored implementation lessons from CLS
- … I don’t recall discussing it before
- … We have this input exclusion concept and it’s tricky to get right
- … LayoutInstability API reports every layout shift for every animation frame
- … Signal for hadRecentInput and whether there was a user interaction within the last 500ms
- … why? CLS is meant to measure amount of unexpected layout shifts, e.g. before user input especially
- … On the other hand, shifts coming after a user interaction are fully expected
- … Excludes some inputs, but not gestures that initiate scroll
- … Early on we considered resizing viewport as an exclusion, as this causes an expected relayout
- … So not an interaction, but shifts report as if they had a recent input.
- … We ran into more examples like zoom features (pinch), changing device pixel ratio, translate feature, back/forward and system notifications
- … more examples like “find in page”, which can match hidden content which can expand collapsed elements
- … visibility changes, BFCache resumption
- … We think all of those are in the same spirit of exclusion windows
- … There’s an issue filed, not yet added to spec
- … Issue 110 tracks this https://github.com/WICG/layout-instability/issues/110
- Dan: I don’t recall, what is the behavior with regard to hover events, some pages resize things on hover that can push things around
- Michal: Doesn’t count as an input for exclusion, mouse-move or hover don’t
- … We recommend to do in a way that is not layout inducing
- Yoav: Similarly for LCP, which is something I’ve been dealing with this week, zoom widgets and things like that are counted as LCP once a user has hovered over
- Dan: Like product gallery? Very common
- Yoav: Yes
- Dan: Problematic, because LCP and CLS things that are intentional are problematic to count as an undesirable behavior
- Yoav: On LCP front I agree, trying to estimate the size of the problem. Once we understand how impactful it is, decide if we should/could create heuristics around that
- … We can’t just exclude all mouse moves, as it would exclude a lot more than desired
- … If you have specific examples that would be awesome
- Dan: No examples on top of my head, idea where you want to resize things after hovering
- … Concept of ignoring after back-forward is potentially problematic in context of trying to support Single Page Applications. Back-Forward should count as another page. Ideally you’d want to measure LCP and CLS all over again.
- … Seems like a decision that might need to be rethought at a later date
- Yoav: I don’t think that conflicts, for traditional navigations, the initial layout doesn’t count as a shift from the blank page or previous page. So ignoring CLS as a result of an interaction from a navigation doesn’t mean we can’t take CLS into account after that once we can monitor soft navigation
- Michal: We know the problem of slicing of an SPA, and we want a solution to that. But even within a single route/view there could be use of back-forward for other purposes.
- … We’d still want that feature even if we do macro-level slicing
- Timo: With regards to back-forward state in a SPA, I assume that would also apply to popState?
- Michal: Yes
- Timo: As far as hover, I think a lot of cases where hover results in a visual change. But I feel like those triggering a layout shift may be less.
- … For example, absolute-positioned things may not shift down other content. Things appearing or getting larger, as long as it’s done through translation and scaling, it may not push down everything else and result in a layout shift. If it does, it’s a nuisance to the user if it does that.
- Yoav: Michal have you from a spec perspective, all those different browser UI interactions, are not necessarily specified today. Have you given some thought to how that could fit in a spec?
- Michal: Spec has two places where there’s room for implementation and implementor flexibility. I don’t know that all the triggers are spec-able, but the e.g. concept of changing viewport size. List out a few examples of things that could lead to this.
- Yoav: Changing viewport size is a spec’d concept, just not how the user triggers it
- … Would assume Zoom is specified
- Michal: Right now the way these things are signaled is the hadRecentInput flag, meaning is kind of getting stretched
- Yoav: Seems semantically equivalent
Summary:
- Currently it’s hard to manage GC lifetimes of user-timing entries without clearing all of them. It’s also impossible for tools to highlight some user timings but not others.
- The issue mostly talked about the former, but there was strong consensus on the call that adding namespaces to User Timing would solve both issues.
Minutes:
- Yoav: Hard to clear out UserTiming entries from timeline without clearing entries that are ongoing
- … We have clearMarks() and clearMeasures() methods, but they aren’t necessarily granular enough
- … You can pass a name, but in this case there could be multiple async tasks
- … Marks and measures of those tasks could have same name
- … If you’re clearing one of them, you’re clearing all of the same name
- … Cumbersome to work with
- Timo: As maintainer of qunit, we added UserTimings and markings, because it’s hard to manage. We now just do calls to performance.now() and maintain it ourselves and get garbage collection
- … Not really found a good use for it, same for Wikipedia. We had a number of these but haven’t expanded their use
- Yoav: If you had a more ergonomic way of managing their lifetimes, would that help?
- Timo: Depends on benefits, main benefit for us is Dev Tools integration
- Yoav: Additional benefit is for RUM provider to have a standard interface
- Timo: We also use WebPagetest and collect through there
- Dan: Agreed that main benefit of mark and measure is integration with tooling, otherwise you can just use performance.now()
- … With tooling it could be useful, assuming the tools can also utilize this extra information in a way
- … For example, in Dev Tools being able to show or hide in perf tab, only marks/measures marked in a certain way
- … For example React, you may want to show/hide measures for those
- … e.g. they use a unicode indicator in that contenxt
- Nic: Related to namespacing, I believe we had another open issue about that. At one point there was a proposal to use a colon to separate namespace from issue
- Katie: +1 the idea of namespacing, idea we’ve run into multiple times where we added our own prefixing functionality. Our perf beacons have an observer queue, and we collect everything in queue. Nice benefit is for engineers to add their own perf timing metrics, they can use the browser API and we can automatically collect that.
- … Have the issue of random third-party plugins or browser extensions, they will be throwing their own timings in and we don’t have any control over that.
- … We’ve clobbered each other, clearing out timings or they are doing such, causing conflict
- … In spirit of encouraging more usage of native APIs, namespacing would help solve some of these issues
- … Could use namespaces for page transitions, e.g. in SPAs, for just your new page has a new namespace
- Yoav: clearMarks() from this namespace, and only clear for those marks
- Timo: +1 for namespace, for React, they prefix with magic symbol.
- … Having a well-defined separate namespace, you can visually distinguish better in dev tools and such. I see a lot of UX improvements you can make once you have that separated.
- … Have apps allow to be opt-in or opt-out by RUM, maybe not attached to global RUM timeline
- Yoav: Explain that last bit more?
- Timo: A separate timeline that is only used for the library and not exposed to dev tools or ot others
- Dan: From my perspective namespacing is especially useful if it’s integrated with tooling, and visible to
- Timo: In Dev Tools you could have separate collors, or you could show/hide based on the namespace
- Michal: To tack onto the tooling question, I know Chrome we use UserTiming for two purposes, we use them from the site but also internally for events on the timeline like page load. Might also be worthwhile to see if people are using those.
- Nic: We used to have “standard” UserTiming names, but those are no longer in Level 2 or 3 of the spec
- Yoav: After everyone expressed enthusiasm for namespaces, I’ll talk about my proposal that doesn’t use namespacing
- … Allow users to pass on an array, other than just a name, of mark/measure objects that you’re getting from UserTiming to clear out those entries
- … If you have a async task you’ll need to collect entries that you want to clear marks or measures
- … This may or may not be a good idea, and possibly orthogonal to to namespace
- Dan: I don’t think we can rely on library authors to do that, or to know to do that. When would a library like React do that?
- … Another possibility is instead of namespace at top of API, we could add the option to the options object when calling mark() or measure()
- … Primary motivation isn’t to remove unneeded marks or measures, but ability of filter my view, which only namespaces can give you
- Timo: But we also do have the GC issue to consider
- Michal: In relation to SPA, there’s a single node environment, on the web we navigate and it resets that page and all measurements. In React, you have a single timeline with all those transitions and things, each route within a particular SPA may want to isolate from other routes to be able to track that timeline.
- Dan: In tooling, I’m not recording such lengthy durations, so segmenting isn’t as useful
- Katie: I think it could be either-or, from developer tooling perspective, I’d assume all the super verbose UserTimings that React reports to you, hopefully you don’t have that in your production environment, but in developer environment you can use it to differentiate for each route.
- … Having to keep track of all your mark and measure objects in order to remove them later, puts the challenge on the developer. We have problems all the time with IntersectionObserver and folks not letting go of references, so I’d worry that we’d end up in same GC collection.
- … There’s something nice about namespaces, so you know once reference to that object is done, it’s removed
- … Developers may not know to think about GC
- Yoav: I agree we shouldn’t introduce C++ concepts around memory management into the web
- … Dan you may want nested namespaces, top-level React, plus new namespaces for each page
- Michal: In an infinite timeline, you need to be able to segment a timeline and clean it up. Multiple libraries in a context of a request and want to visualize them together
- Yoav: Not necessarily nested namespaces, but overlapping ones. Two libraries with overlapping namespaces
- … Katie, associating namespace with an object, when that object is cleared they’ll all be removed.
- Yoav: Be hesitant to create a new Performance Object per task, but attaching a namespace to an existing JS object seems like a smaller change to how performance timeline works.
- Katie: If we are in world where multiple overlapping performance timelines, what we do with things that are global like NavigationTiming object? How would you combine them?
- Yoav: That’s why I’m not eager to have a performance timeline that’s not a global object
- … RUM or central service provider needs it to be global
- Tom: Instead of always passing in static string as a namespace, you could consider querying namespaces, modeled as a tree, e.g. “context.context” or “*”
- Yoav: Get entries by namespace
- Michal: Or “tags” instead of namespaces