GithubHelp home page GithubHelp logo

wicg / layout-instability Goto Github PK

View Code? Open in Web Editor NEW
157.0 157.0 26.0 309 KB

A proposal for a Layout Instability specification

Home Page: https://wicg.github.io/layout-instability/

License: Other

Makefile 100.00%

layout-instability's People

Contributors

dholbert avatar ehanley324 avatar npm1 avatar rik avatar saschanaz avatar skobes-chromium avatar yoavweiss avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

layout-instability's Issues

What events trigger LayoutShift Performance Callback?

  • LS computation is skipped for a short interval on user input. Does that mean the LayoutShift algorithm always runs in the browser otherwise?
  • Are there any (heuristic) events after which LS observer cb may fire?

clarify LS Score

In reading the explainer I wondered about the units of LS Score. Is it just "fraction of viewport"? Might be nice to clarify that.

I would also have appreciated more examples. Two specifics:

  1. In the example provided the border boxes overlap. What if they didn't? Suppose there was a div at the top that took 10% of the viewport, and it moved to the bottom of the viewport. Would that the LS Score be 0.2?
  2. What if the element moves out of the viewport? This happens frequently in my experience, where a footer might appear in the viewport but then get pushed below the fold. If that footer took 10% of the viewport and then got pushed out, would the LS Score be 0.1?

ignoring transforms (spec issue)

Chrome's current implementation of layout stability generally ignores transform changes, which we think is desirable, because

  • changing an element's transform doesn't affect layout of surrounding content, and
  • sites that incorporate transform animations would otherwise be overly penalized.

However the spec as written doesn't technically permit this: its definition of "starting point" incorporates offsets from transformed ancestors, so the algorithm "identify an unstable element" will return true for a transform-changing container as well as its descendants.

Fixing the spec to match the implementation seems a bit tricky. For example, we still want to consider transforms in computing viewport intersection for the impact region. And, we don't want to ignore a real layout shift just because it may have a transformed ancestor.

It seems to me that we want the following properties:
(a) If an element's transform changes, but it would not otherwise be an unstable element, then it is not an unstable element
(b) If an element's nearest transformed ancestor is not an unstable element after applying (a), and its transform-relative starting point has not changed, then it is not an unstable element
(c) Otherwise, run the current algorithm

This introduces a new concept, "transform-relative starting point", which would be the flow-relative offset in the coordinate space of the nearest transformed ancestor.

@npm1 points out that "would not otherwise be an unstable element" in (a) is hard to reason about. I'm trying to find a good way to express this. Maybe we need some concept of position-without-transform just for (a).

Would like to hear others' thoughts, especially @tabatkins

Minor mistake in code example

The example show in the spec instructs users to call observer.takeRecords() to "force any pending records to be dispatched", but the takeRecords() method actually returns pending records rather than dispatching them.

The example should be updated to run the callback on the returned entries rather than just calling it.

make it easier to determine what is a "bad" DCLS value

I implemented the DCLS code provided here and tried it on a few pages. I got values that ranged from 0.5 to 1.5. My initial reaction was wondering what was a good score and what was a bad score. It sounds like DCLS could get very large - in the thousands potentially.

I think it would be better if the score could be on a fixed scale - say 0 to 100. This would let people have a better understanding of whether layout instability was a priority issue. Since it's not a time-based metric, it might be better to invert it so a score of 100 is perfect (like Lighthouse).

(I read the previous discussion about measuring Layout INstability vs Layout STability. Sorry if this rehashes that debate.)

The "move distance" metric imposes a strange penalty on extremely-offscreen content (depending on how far offscreen it was)

Suppose you have an element that is positioned offscreen (e.g. with position:absolute; left: -50px) which then snaps onscreen (e.g. by changing left to 0)

The spec currently requires us to consider how far the element moved, as one of the inputs to layout shift. (It moved 50px in this example, so it would contribute 50px to the maximum move distance calculation, which then determines the Distance Fraction)

Now: if the node's initial offscreen position were left:-1000px, then we would instead contribute 1000px to the maximum move distance calculation, and this node would have a much harsher impact on the Layout Shift value.

This doesn't really make sense. From a user's perspective, this is content that has just appeared, and the user doesn't know & doesn't care how far offscreen it was before it appeared. (It's not any better or worse for its prior posiiton to be at -1000px vs. -50px, as long as it was entirely clipped at that point, so the score shouldn't give any advantage to one value or another.)

It feels like we should treat this scenario the same as we treat content that was freshly-created (i.e. don't consider it "moved" at all; consider it as having no last-position), in order to capture that actual user experience.

Consider excluding user-scroll + scroll-anchor in the same frame from being penalized

From my understanding the instability (shift) is detected by following this rough algorithm:

  • if element stuck to viewport (based on prev/new positions), not a shift
  • if element stuck to document, not a shift
  • if element does anything else, it's a shift

(credit to @skobes)

However, there seems to be another case: an element is stuck to a 'virtual' document whose position is kept intact via scroll anchoring, but it is still able to move around via user scrolls.

As an example, consider content-visibility: auto element that may change size as it leaves the viewport (technically, leaves a padded area that is centered around the viewport). For a sibling element that is on screen two events affect its position:

  1. The scroll anchoring effect which ensures that the visible element does not shift position
  2. The user scroll that moved content-visibility: auto element off screen in the first place.

The desired net effect here is that the element visually shifts by the user scroll amount from 2. However, here the desired effect is neither "sticking to the viewport" nor "sticking to the document" since both positions shift: viewport position is shifted by user scroll, and document position is shifted by the scroll anchor.

Chromium's implementation of this does report a layout shift. I think we should change this behavior.

As a side note, this is not specific to content-visibility: auto element since the same behavior can be polyfilled with an intersection observer that changes size of elements off screen

Spec's usage of the term "line box generated by N" might be imprecise/incorrect (where N is a text node)

In this section...
https://wicg.github.io/layout-instability/#sec-terminology
...the spec defines the "starting point" and "visual representation" of a text node N in terms of "the first line box generated by N".

I think this might be misusing terminology -- I'm not sure it's correct to say that text nodes "generate line boxes", really. They're contained within line boxes, and they do (in aggregate) cause line boxes to exist, but their block container (or their inline formatting context) is really the thing that generates the line boxes.

As a concrete example, consider e.g. a line box which is formed to contain all of this content (with many individual text nodes): 1<a>2</a>3<i>4</i>5<u>6</u>7 . It would be misleading to say any individual one of the text nodes here "generated" the line box. Really, the line box was generated by the block container / inline formatting context, and it contains boxes for all of these text nodes, I think.

So, anyway -- assuming that the spec really wants to refer to the whole line box (rather than just the box around the text): maybe it wants to say something like "the first line box that contains a piece of N's content"? (or use "contains" / "participates-in" terminology, rather than "generates")

Add an example computing CLS including iframe

The CLS is defined in the non-normative section and it's not super clear to me how you compute it. In particular, the subframe weighting factor could change over time? (i.e. should it be computed on every frame, or how does one account for an iframe that shifts or moves after user interaction and hence becomes more/less visible within the viewport).

CLS issue caused by FIXED position elements having z-index

Chrome Version - Version 88.0.4324.41 (Official Build) beta (64-bit)

Steps to re-produce

  1. Go to https://direct.asda.com/george/women/dresses/D1M1G20C1,default,sc.html

  2. If you are shown a cookie banner, click 'accept all'

  3. Now do a hard refresh of the page (Ctrl+R)

  4. Ignore any CLS at this stage as we are interested in CLS caused after initial load when we scroll (00:11 Sec marker in video below.. I clear any CLS observed from hard refresh)

  5. Start scrolling down slowly and observe layout shifts in console (00:13 Sec marker in video below)
    const po = new PerformanceObserver((list) => { for (const entry of list.getEntries()) { if (!(entry.hadRecentInput)){ console.log(entry); } } }); po.observe({type: 'layout-shift', buffered: true});

  6. You will see element div.refinements__footer.zerorefinements appearing again and again as you scroll.

  7. This element is not at all visible to user at this stage and there is no visible layout shift happening for the user. In attached video, to show this element, I have added border and border-colour. This element appears when you click on 'FILER' button and select any refinement values. You will see a button called 'View Items'. This DIV wraps that button.

I have recorded these steps in video below...

https://www.awesomescreenshot.com/video/2073259?key=28541cc1d1868898871719364840a842

I see that in Chrome88 change log there is a change with respect to 'fixed position elements'. I wonder if what I am seeing is some sort of regression due to this change OR correct behaviour as per metric specs... If yes, what is the expectation from devs to fix such issues?

image

@philipwalton @anniesullie @patrickhulce

I tried same steps on Version 85.0.4183.121 (Official Build) (64-bit) and I don't see these layout shifts on this version

clarify starting point for fragmented elements

When an element has multiple fragments due to pagination or multi-column layout, its starting point should be the offset of the first fragment. The spec should be clarified in this regard.

focus on high priority elements

There are lots of rendering metrics that should be ignored because they give every pixel in the page the same weight, even though we know that site owners and users focus on high priority pixels like headlines and hero images. Largest Contentful Paint is a great move of applying heuristics in an attempt to measure the rendering of pixels that matter.

I think the same should be considered for Layout Instability. Personally, I most notice layout jank when I'm reading the main content of a page: headlines, hero images (or more often the caption under a hero image of news sites), and lead paragraphs. Some of these would be hard to identify (eg, lead paragraph), but headlines and hero images could be identified using logic similar (identical?) to that used for Largest Contentful Paint.

True, true - it is inelegant when a social media widget or ad has a layout shift, but I don't think that matters as much to site owners and users as layout instability related to the critical content in the page.

Could we get a version of Layout Instability that focused on critical content?

Clarification about Hover causing layout shift

I raised a bug here https://bugs.chromium.org/p/chromium/issues/detail?id=1161025#c6 but this may be a Spec question

You can see that in bug reported, issue is caused by hover and looking at the spec (https://github.com/WICG/layout-instability#recent-input-exclusion) , I see that 'Events caused by pointer movement or scrolling do not count as "input" for the purpose of the recent input exclusion and the input-related attributes on the LayoutShift entry.'

So as per spec, it's reporting hadRecentInput as 'false' and counting towards CLS but is this correct? From user perspective, in this specific case, I don't see any layout shift and negative customer experience.

And how a site owner will fix something like this?

Elements without content shouldn't affect LS

Hi there from the Lighthouse team πŸ‘‹ :)

I'm bringing up an issue that was been raised a few times over in Lighthouse where we expose the CLS of the page (GoogleChrome/lighthouse#10873 is a particularly useful discussion that highlights several rough edges of CLS if you're interested).

The gist is that when dynamically loading in content into an app shell, you have to do some CSS gymnastics to position your loading spinner to ensure that the empty positioning divs don't artificially inflate CLS.

A particularly rough example is https://melodic-class.glitch.me/cls-empty.html which clearly has no user perceived layout shift yet gets a CLS of 0.426

I'm wondering if it could be considered that elements without any content (text or images) are excluded from layout shift.

arbitrary constants in the spec?

I noticed these:

Probably there is a good rationale for these values, but the spec does not explain from where they are coming.

(side note: As a comparison, the intersection observer spec which deals with similar approximations, introduced rootMargin / threshold values, so they are configurable by users)

Layout Instability Spec needs to define what happens, in cases where its prescribed algorithm would divide by zero

The Layout Instability Spec has a few spots where it calls for dividing one quantity by a second quantity, and it's possible for that second quantity to be zero.

Specifically:

The distance fraction of a Document D is the lesser of

  • the maximum move distance of D divided by the viewport base distance, or
  • 1.0

And:

The impact fraction of a Document D is the area of the impact region divided by the area of the viewport

If we're dealing with a document in a 0x0 iframe, then these computations will both produce a division by 0, which produces an undefined result here. Of course 0-sized-iframe isn't a particularly useful case for layout instability; but the spec needs to define what browsers should do if they're asked to compute this metric.

One simple suggestion: we could simply floor both quantities (the viewport base distance and the area-of-the-viewport) at 1, so that we'd be dividing by 1 instead of by 0.

Alternately (maybe better), we could add an up-front special case to say that these fractions are both defined to be 0 if the viewport base distance is 0.

The spec should make it clearer whether `transform` affects "visual representation" and layout shift

The explainer and spec don't seem to agree on what the impact of CSS transform is, with respect to layout shift.

The spec:
(1) doesn't mention the word transform at all, ever.
(2) Defines layout shift in terms of the "visual representation"
(3) Defines "visual representation" in a way that's not immediately obvious as to whether it includes transforms or not.
https://wicg.github.io/layout-instability/#sec-basic-concepts

The explainer:
(4) ...says that "Changing an element's transform affects its visual representation" (direct quote, emphasis added, note the use of the spec term "visual representation")
(5) ...says that transform changes aren't treated as layout shifts
https://github.com/WICG/layout-instability/blob/master/README.md#transform-changes

Concerns:

  • Taking (2) and (4) together, it seems quite clear that transform does impact layout shift. (But that disagrees with (5).) But maybe the explainer is just misusing the spec's specially-defined term "visual representation"?

  • The expectation should be made clearer in the spec itself. If we want to exclude transforms (and I think we do), then the spec should explicitly say something about that; possibly as a Note after whatever definition / concept-usage that it's currently leaning on to implicitly exclude them.

layout instability spec needs to clarify whether (and which) unpainted nodes are considered or not

Right now, the layout instability spec officially considers a moved element as contributing to instability if the element "generates one or more boxes", as defined here: https://wicg.github.io/layout-instability/#visual-representation

However, this may not be practical for implementations, and it seems to be inconsistent with how the feature is implemented in Chrome.

Consider for example this testcase, which has an element with visibility:hidden that gets shifted (via the insertion of another node before it): https://jsfiddle.net/yqr570ex/

In Chrome 84, this testcase does NOT trigger a reported Layout Shift right now, even though the visibility:hidden element definitely "generates a box". I've included a few other notable CSS classes that you can set on the container for the shifted element (the thing with id="giveMeAClass"). And when the shifted element's parent has...

  • visibility:hidden: it does NOT trigger a layout shift report in Chrome (as noted above)
  • contain:paint and zero size (i.e. fully clipped): it does NOT trigger a layout shift report in Chrome.
    ...vs.:
  • opacity:0: it DOES trigger a layout shift report in Chrome.
  • contain:paint and a small nonzero size (i.e. almost-fully clipped, nothing actually painted): it DOES trigger a layout shift report in Chrome.

I think both the spec & Chrome need to be updated to have a coherent story on which of these should be considered. The final one here (contain:paint and small nonzero size) makes sense, but the other three seem like they should be consistent & should be clearly defined by the spec; right now, the spec seems like it would call for them all to trigger layout shifts.

exclude elements that transition from hidden to visible

The spec currently excludes visibility:hidden elements from the unstable node set, but it doesn't exclude elements that are now visibile but were hidden in the previous frame.

We should exclude such elements for the same reason that we exclude visibility:hidden generally. A visible shift requires visibility in both the previous and current states. Transitioning from hidden to visible is more like inserting new content, which CLS intends to allow.

crbug.com/1152869

The spec disagrees with developer documentation about whether precise layout-shift values/thresholds should be relied on

The Layout Instability spec seems to be in conflict with Google's articles/documentation on how layout shift values should be used & thought about.

From the spec:

Developers are advised to avoid relying on the precise value of the layout shift score, as the metric might evolve over time, and user agents might compromise precision in the interest of calculation efficiency.
(source: WICG spec text)

...vs, from Google's developer articles:

To provide a good user experience, pages should maintain a CLS of less than 0.1.
(source: Web.dev article, another web.dev article, implicit in in "page speed insights" report ranking)

(Technically the spec text is about individual LS values rather than the CLS, but it still applies to the CLS score by extension, since the CLS is a sum of LS scores.)

The above-quoted spec text seems to be saying that the precise value (and precise thresholds like 0.1) aren't meaningful -- it sounds like it's saying authors should prefer to watch for increases/decreases rather than reasoning about any one precise value. However, this disagrees with the web.dev articles and pagespeed insights reports, which treat the precise values 0.1 and 0.25 as special thresholds.

If my reading of the spec isn't the intended meaning (i.e. if values are indeed intended to be meaningful on their own, rather than just metrics to watch for increases/decreases), then maybe that line of spec text should be reworded to clarify what it's trying to say?

`content-visibility: auto;` makes CLS go bananas

Hi, I've already posted this as an issue in the web-vitals repo but got referred here πŸ™‚

GoogleChrome/web-vitals#108

It seems like by using the new content-visibility: auto; the measured layout-shifts keep increasing while the user scrolls the page, even though the shifts are happening outside the visible viewport - is this a desired behavior?

The reported CLS-values can easily get to 1 and above just by scrolling down the page (even though for the user everything looks fine and non-jumpy).

Ignore layout shifts due to user-initiated content dragging

Many web applications make content resizable/draggable in a way that's triggered by the mousemove event, which at the moment Chrome implementation of the LayoutInstability API ignores w.r.t the hasRecentInput flag.

Could we spec this in a way such that mouse/pointer move events aren't ignored from being included in layout shift attribution if they're in between mouse/point down and up events?

Here's an example of a site that exhibits this problem: https://philipwalton.github.io/responsive-components/ (and a video of it happening).

The spec and explainer seem to disagree on what "Cumulative Layout Shift" means

Minor issue I noticed when reviewing the explainer / vs. spec:

  • The explainer goes into some detail to define and differentiate the document cumulative layout shift vs. the cumulative layout shift (the latter of which is computed by performing an aggregating operation across all iframes in the document).

  • However: the spec only mentions the latter term ("cumulative layout shift"), and it uses it with a meaning that seems closer to the other term (i.e. its usage doesn't have any cross-iframe aggregation).

To put it another way: when the spec says "Cumulative Layout Shift" (and cumulativeLayoutShiftScore in the usage example), it's using it in a sense that corresponds to what the explainer defines as "Document Cumulative Layout Shift".

Alternative to DCLS that better represents user experience of jank

I'm not convinced that DCLS is representative of how users perceive layout instability. DCLS would weight several layout shifts in a short space of time as separate "janks", however people typically perceive delays of <100ms as near-instantaneous.

An alternative might be to group layout shifts into time buckets, and sum the biggest layout shift for each bucket. I believe this approach would produce a score that more closely represents how a user experienced the janks.

I've made a contrived example here that demonstrates what I'm talking about. This page makes several small janks ~10ms after one another, and then one bigger jank a second later. DCLS takes all of those small janks into account, but I believe most people will perceive it as a single jank. https://wildlyinaccurate.com/webdump/dcls.html

Layout shift reported without actual visual shifting for resized fixed iframe

this is a re-post of this Lighthouse issue

Provide the steps to reproduce

Create a fixed iframe that is being resized with an element with it that has also a fixed positioning to stick it to the right edge.

screencast 2020-09-14 12-06-54

The border has been added on the outer element to visualize what is changing (the fixed container of the iframe on the page).

What is the current behavior?

CLS is being reported.

What is the expected behavior?

No CLS should be reported here - there is no visual effect for the user.

I understand that the use case here is very specific, but it shows that the current heuristics do not account for more complex scenarios. It's not sufficient to compute the layout shift of the element in relation to its viewport - the computation should account for nested frames.

Given that this is a user-centric metric and a user is not impacted in a meaningful way in scenarios like this then it would be great if this just wouldn't result in a false positive (from the user's perspective).

CFC: adopt to WebPerfWG as a Working Draft

The proposal was throughly discussed in the WebPerfWG's calls and meetings, and I believe it is in good shape to be adopted as a Working Draft.
Please vote using πŸ‘, πŸ‘Ž or comment.

explainer should perhaps explain how much the metric is intended to evolve over time and vary between implementations

I think one of the major questions around the design of this spec is the following: it seems like figuring out what developers should optimize for in terms of stability during load is a question that has active research. At least, I don't think there's an agreed-upon answer for what the perfect thing to measure is.

So for this specification, it feels like there's a tension between (a) specifying something that's precisely interoperable versus (b) specifying something that can be improved on over time (e.g., where browser engines could have different opinions on what type of instability is best/worst for their users, and could improve that metric over time).

I'm curious both where you think the current spec fits along that tradeoff/continuum, and what you think advantages/disadvantages of shifting to a different point along that continuum would be. This seems like something that could perhaps be discussed in the explainer.

Something else that I think either the explainer or the spec should explicitly state: is this spec intending to evolve the definition of the metric over time in response to feedback, or is it intended to become stable at some point?

(I got here from w3ctag/design-reviews#393.)

When is the right time to start recording layout shifts?

Per the README:

addEventListener("load", () => {
  let DCLS = 0;
  new PerformanceObserver((list) => {
      list.getEntries().forEach((entry) => { DCLS += entry.value; });
  }).observe({type: "layout-shift", buffered: true});
});

The load event seems like a deliberate choice, so I'm curious about the reasoning behind it, as opposed to an event like DOM Content Loaded. By starting at load time, won't that exclude layout shifts caused by unsized <img> elements in the document? Is the intention only to capture layout shifts caused by asynchronous resource loading?

Define how much data should be buffered (also: does 'buffered' impose a substantial cost on the whole web here?)

Right now, the Layout Instability spec only has one mention of buffered, in the usage example.

However, it's unclear what this means & what the requirements are for it. The buffered flag is defined (loosely) in https://w3c.github.io/performance-timeline/ which has an important note that needs to be addressed in the Layout Instability spec:

NOTE
The number of buffered events is determined by the specification that defines the metric

Also:

and buffering is intended to used for first-N events only; buffering is not unbounded or continuous.

(emphasis added)

Accordingly: please clarify how many reports (if any) should be buffered here.

Also: I'm not sure low numbers are usefully "cheaper" here... Independent of the specific number, I'm a little concerned in general about supporting buffered at all for this metric, because I think that implies that the browser needs to perform layout-instability-calculations everywhere -- for all web pages, for every animation frame -- in order to have however many buffered historical values available to report just in case the web page suddenly registers a layout-instability observer with the buffered flag.

Even in the extreme case where buffered only requires you to report 1 or 2 old observations, it would still mean you have to compute layout instability data for every frame for all time, because you don't know when the page is going to suddenly register and ask for your buffered observations. They can't be computed lazily/on-demand, because they're about past relayout behavior.

Granularity of measurement?

Related to the interoperability issues mentioned by @dbaron in #23, and to the questions raised by me and @lknik on the TAG review thread at w3ctag/design-reviews#393.

I'm interested in what the effective precision or granularity of the score may be. In particular, might there be a granularity at which we might expect to have some level of interoperability? And, would making the score more granular help erase meaningless variation in the score?

For example, could we potentially allocate a limited number of buckets such as (per @skobes' comment) low, medium and high, and return an enum indicating which of these buckets the computed score falls in? What likelihood would that have of being both useful and interoperable? Would a finer granularity be meaningful?

clarify treatment of scrolling

The intent is that scrolling does not automatically cause layout shifts, either in normal-positioned content or in fixed-positioned content. The spec should be more explicit about this.

Spec should clarify whether or not this is intended to serve as a "layout-changed observer" (I think it's not?)

It may be tempting for web developers to use the Layout Instability API as a way of tracking when elements move (for any reason), as a way to receive callbacks when they need to recompute the positions of other related elements (e.g. overlays, focus rings).

There's a blog post here that recommends doing exactly that -- it describes a number of other things too, so you can do find-in-page for "layout shift" to jump to the relevant details:
https://www.notion.so/Focus-Rings-4459faa9d1f643728ca8dde145a89900

(see also: a tweet about this in https://twitter.com/aweary/status/1313266406641864706?s=20 )

So this blog post is describing a way to use the Layout Shift API as a callback that fires when layout changes (specifically when it changes in a way that moves elements around); and it uses this as a hook for the web-developer's JS to run and make some resulting positioning adjustments to overlays and such.

Is this an intended-to-be-useful use case for this API? The problem that comes to mind first is the magic "3px" threshold that's currently hardcoded in spec (which means: an element that slowly moves < 3px per animation frame won't trigger a layout shift report, even if it continues moving a long distance at that rate; see first example in #53 (comment) . So this blog post's approach wouldn't ever receive a callback if they happened to only have slowly/subtly moving content.)

If in fact this "layout observer" sort of thing is not a use-case that this API intends to robustly support, then it might make sense to make that clear in the spec...

Is `visibilitychange` really the right signal for when to aggregate layout shift?

Right now, the spec section 1.1 says:

A "final" score for the user’s session can be reported by listening to the visibilitychange event, and taking the value of the cumulative layout shift score at that time.

(This is in a non-normative section, but it's still worth considering this recommendation about how to use the reported metric.)

Is the visibilitychange event really what we want to suggest here? And if so, could we add a sentence or two to explain what it's expected to capture, & perhaps to consider (and hopefully address) anticipated concerns about this event?

I admit I haven't worked with visibilitychange much, so I might be missing something -- but based on its documentation and a demo, I see a few problems that seem to make it problematic for in-the-field analytics on this.

Depending on user behavior, this event...

  • Might fire way too often -- This event is fired whenever the user switches tabs; are we expecting that authors will really want to aggregate & submit their "final" layout-shift metrics when that happens, and repeat that aggregation every time that happens if the user repeatedly switches back and forth?
  • Might not fire ever [to a first approximation], or at least not soon enough -- it looks like an arbitrarily large amount of time can pass before this event fires. e.g. Suppose a user opens your page, and they leave it open in its own browser-window -- then, this event will never fire, until they quit their browser, which they might never do. If the web developer is waiting on visibilitychange to send aggregated analytics, they may ~never get their report -- or maybe-worse: when they do get their report, its value may be the summation of several days' worth of layout shift metrics, which could produce a very large and ~meaningless metric. (For a largely static page, the metric may stabilize & stop changing & perhaps could be usefully reported after an arbitrary delay; but for any site with some dynamically-updating portion, e.g. Gmail/twitter, the metric would monotonically increase over time and could be arbitrarily large when visibilitychange fires.)

Explain (and perhaps make configurable) the magic number 3 in "3 or more pixel units" (when determining which nodes are shifted)

Right now this section...
https://wicg.github.io/layout-instability/#sec-unstable-nodes
...defines "shifted" as the starting point having moved by 3 or more pixels in some axis.

Why the magic number 3?

A few thoughts about (and responses to) some possible explanations:

  • If the point is to avoid penalizing small shifts: doesn't the "distance fraction" already sort of account for that?
  • If the point is to simply reduce the computational cost on the browser: that reduced computational cost seems maybe nice, but it's not clear to me that 2px shifts are common enough to have their own special case here.

It seems like maybe this threshold should be configurable in the API -- or if not, there should be a clear explanation somewhere for why 3px is The Right Threshold.

Specify expected behavior for overflows and containment

The current spec seems to imply that overflowing contents should report their own shifts, but this requires that the browser to traverse the subtree whose root is shifted.

We could define how we should detect and report shifts for ancestors and descendants. For example, can we define that we don't need to report descendants' shifts if they don't shift in the ancestor? If yes, can we define that the ancestor should also report its overflow in its shift, to avoid tree walk into the subtree if possible?

This is particular important when we deal with css contain. We don't want to traverse the subtree of css contain in particular cases.

Measuring Layout Instability / CLS from IFRAMEs

The spec mentions that:

The cumulative layout shift (CLS) score is the sum of every layout shift value that is reported inside a top-level browsing context, plus a fraction (the subframe weighting factor) of each layout shift value that is reported inside any descendant browsing context.

and

The subframe weighting factor for a layout shift value in a child browsing context is the fraction of the top-level viewport that is occupied by the viewport of the child browsing context.

This seems like the right thing to do -- iframes affect the visual experience just as much as any other content.

I've found in practice, IFRAMEs aren't currently being accounted for CLS by synthetic or RUM tools:

  • Lighthouse doesn't currently take IFRAMEs into account for the CLS score (GoogleChrome/lighthouse#11500), though it does show shifts from IFRAMEs in its diagnostics section. This will probably be fixed over time.
  • RUM analytics packages like boomerang.js, perfume.js, web-vitals and LUX all only listen for layout-shift via a PerformanceObserver in the top-level frame.

I want to make sure RUM and synthetic tools are able to report the relatively-same score. When synthetic tools like Lighthouse start tracking CLS in frames, it may be hard to keep scores similar for some sites via RUM. That can lead to confusion of the metric and questioning its reliability.

For RUM, it would actually be hard to take layout shifts from frames into account:

  • You'd need to register a PO for all every frame on the page
  • Technically, you probably should crawl the entire frame tree and register in grandchildren/etc
  • There may be short-lived frames (that have disappeared by the time RUM comes along), or dynamically introduced frames (that are hard to efficiently know about new ones) that would need PerformanceObserver registered for
  • Shifts may come from cross-origin IFRAMEs which cannot have a PerformanceObserver
  • Even if all of those shifts were somehow captured, calculating the subframe weighting factor (e.g. viewport percent) seems non-trivial (and time sensitive)

In light of all of this, I'd like to explore if we can try to have the top-level frame emit layout-shift data for all of its children/grandchildren/tree with an already-calculated subframe weighting factor attribute.

This could possibly be solved by w3c/performance-timeline#86 and could also benefit from w3c/resource-timing#210.

I realize that data from cross-origin frames may not be able to be surfaced, or, they'd need to opt-in somehow like in w3c/resource-timing#210.

Thoughts?

layout instability spec doesn't account for paint-only effects that don't influence css box size (e.g. box-shadow)

tl;dr: Chrome seems to be considering box-shadow as something that contributes to the Visual Representation of a node, which seems superficially reasonable but disagrees with the spec's definition of Visual Representation. So this is a case where Chrome & the spec disagree. Not sure whether it's a spec bug vs. Chrome bug. --> Starting out as a spec bug.

STR:

  1. Load this testcase in Chrome, with the devtools console open (F12):
    https://jsfiddle.net/dholbert/6rw8oqsf/
  2. Make a note of the logged layout-shift value.
  3. Edit the testcase to remove the box-shadow declaration, and re-run the testcase, and look at the logged layout-shift value.

ACTUAL RESULTS: The layout shift value changes.
EXPECTED RESULTS: Per the current spec, the layout shift value should not change.

NOTES:
box-shadow is a paint effect which is defined as not influencing layout. Quoting the spec that defines box-shadow:

Shadows do not influence layout [...]
Shadows do not trigger scrolling or increase the size of the scrollable area.

https://drafts.csswg.org/css-backgrounds-3/#shadow-layers

...while layout-shift is defined in terms of an element's "boxes" (from the box tree):
https://wicg.github.io/layout-instability/#visual-representation

Shadows attach themselves to boxes, but they do not increase the size of the boxes. Shadows do increase the size of the "ink overflow" region -- one possible resolution here would be to redefine the Visual Representation in terms of the Ink Overflow. That would be a somewhat substantial change, though.

Attributes cannot accept sequence types - 'sources'

The recent change to add LayoutShiftAttribution was just imported into WPT in web-platform-tests/wpt#22499

The automatic idlharness file appears to have caught an error:

FAIL message: promise_test: Unhandled rejection with value: object "WebIDLParseError: Syntax error at line 11 in layout-instability, since `interface LayoutShift`:
 attribute sequence<LayoutShiftAttribution> sources;
                                            ^ Attributes cannot accept sequence types"

https://wpt.fyi/results/layout-instability/idlharness.window.html?diff&filter=ADC&run_id=441160005&run_id=460560003

Fix ambiguous language in section 2.2, "has not shifted in $X or $Y"

Ambiguous language in section 2.2 here:
https://wicg.github.io/layout-instability/#sec-basic-concepts

there does not exist an Element P such that
[...conditions...] and:
4. N has not shifted in the coordinate space of the local coordinate system or scrollable overflow region of P.

This language is currently ambiguous -- it's not clear what the "or" means here.

This could be read to mean two very different things:
Interpretation A:
"Either: N has not shifted in the coordinate space of the local coordinate system of P, or N has not shifted in the scrollable overflow region of P"

Interpretation B:
"N has not shifted in the coordinate space of the local coordinate system of P, nor has it shifted in the scrollable overflow region of P."

Please reword to make it unambiguous.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.