Skip to content

Commit ee43a00

Browse files
Elchi3wbamberg
andauthored
Document Layout Instability API (#23007)
* Fix group, redirect overview page * Add layoutshift to general performance pages * Update LayoutShift pages * Apply suggestions from code review Co-authored-by: wbamberg <[email protected]> * Fix more nodes * Expand on why hadRecentInput is useful * Avoid CLS * Fix links * tags -> status * Fix spec list * tweaks as per wbamberg --------- Co-authored-by: wbamberg <[email protected]>
1 parent 8601619 commit ee43a00

File tree

23 files changed

+383
-102
lines changed

23 files changed

+383
-102
lines changed

files/en-us/_redirects.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8771,6 +8771,7 @@
87718771
/en-US/docs/Web/API/KeyframeEffectReadOnly/iterationComposite /en-US/docs/Web/API/KeyframeEffect/iterationComposite
87728772
/en-US/docs/Web/API/KeyframeEffectReadOnly/target /en-US/docs/Web/API/KeyframeEffect/target
87738773
/en-US/docs/Web/API/Largest_Contentful_Paint_API /en-US/docs/Web/API/LargestContentfulPaint
8774+
/en-US/docs/Web/API/Layout_Instability_API /en-US/docs/Web/API/LayoutShift
87748775
/en-US/docs/Web/API/LinearAccelerationSensor/x /en-US/docs/Web/API/Accelerometer/x
87758776
/en-US/docs/Web/API/LinearAccelerationSensor/y /en-US/docs/Web/API/Accelerometer/y
87768777
/en-US/docs/Web/API/LinearAccelerationSensor/z /en-US/docs/Web/API/Accelerometer/z

files/en-us/web/api/layout_instability_api/index.md

Lines changed: 0 additions & 45 deletions
This file was deleted.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
---
2+
title: LayoutShift.hadRecentInput
3+
slug: Web/API/LayoutShift/hadRecentInput
4+
page-type: web-api-instance-property
5+
browser-compat: api.LayoutShift.hadRecentInput
6+
status:
7+
- experimental
8+
---
9+
10+
{{SeeCompatTable}}{{APIRef("Performance API")}}
11+
12+
The **`hadRecentInput`** read-only property of the {{domxref("LayoutShift")}} interface returns `true` if {{domxref("LayoutShift.lastInputTime", "lastInputTime")}} is less than 500 milliseconds in the past.
13+
14+
Layout shifts are only a problem if the user is not expecting them, so layout shifts that are the result of user interactions (such as a user expanding a UI element) are often not considered in layout shift metrics. The `hadRecentInput` property allows you to exclude these shifts.
15+
16+
## Value
17+
18+
A boolean returning `true` if {{domxref("LayoutShift.lastInputTime", "lastInputTime")}} is less than 500 milliseconds in the past; `false` otherwise.
19+
20+
## Examples
21+
22+
### Ignoring recent user input for layout shift scores
23+
24+
The following example shows how the `hadRecentInput` property is used to only count layout shifts without recent user input.
25+
26+
```js
27+
const observer = new PerformanceObserver((list) => {
28+
for (const entry of list.getEntries()) {
29+
// Count layout shifts without recent user input only
30+
if (!entry.hadRecentInput) {
31+
console.log("LayoutShift value:", entry.value);
32+
if (entry.sources) {
33+
for (const { node, currentRect, previousRect } of entry.sources)
34+
console.log("LayoutShift source:", node, {
35+
currentRect,
36+
previousRect,
37+
});
38+
}
39+
}
40+
}
41+
});
42+
43+
observer.observe({ type: "layout-shift", buffered: true });
44+
```
45+
46+
## Specifications
47+
48+
{{Specifications}}
49+
50+
## Browser compatibility
51+
52+
{{Compat}}
53+
54+
## See also
55+
56+
- {{domxref("LayoutShift.lastInputTime")}}

files/en-us/web/api/layoutshift/index.md

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,43 @@ status:
77
browser-compat: api.LayoutShift
88
---
99

10-
{{APIRef("Layout Instability API")}}{{SeeCompatTable}}
10+
{{APIRef("Performance API")}}{{SeeCompatTable}}
1111

12-
The `LayoutShift` interface of the [Layout Instability API](/en-US/docs/Web/API/Layout_Instability_API) provides insights into the stability of web pages based on movements of the elements on the page.
12+
The `LayoutShift` interface of the [Performance API](/en-US/docs/Web/API/Performance_API) provides insights into the layout stability of web pages based on movements of the elements on the page.
13+
14+
## Description
15+
16+
A layout shift happens when any element that is visible in the viewport changes its position between two frames. These elements are described as being **unstable**, indicating a lack of visual stability.
17+
18+
The Layout Instability API provides a way to measure and report on these layout shifts. All tools for debugging layout shifts, including those in the browser's developer tools, use this API. The API can also be used to observe and debug layout shifts by logging the information to the console, to send the data to a server endpoint, or to web page analytics.
19+
20+
Popular performance tools, use this API to calculate a [Cumulative Layout Shift (CLS)](https://web.dev/cls/) score.
1321

1422
{{InheritanceDiagram}}
1523

1624
## Instance properties
1725

26+
This interface extends the following {{domxref("PerformanceEntry")}} properties by qualifying them as follows:
27+
28+
- {{domxref("PerformanceEntry.duration")}} {{ReadOnlyInline}} {{Experimental_Inline}}
29+
- : Always returns `0` (the concept of duration does not apply to layout shifts).
30+
- {{domxref("PerformanceEntry.entryType")}} {{ReadOnlyInline}} {{Experimental_Inline}}
31+
- : Always returns `"layout-shift"`.
32+
- {{domxref("PerformanceEntry.name")}} {{ReadOnlyInline}} {{Experimental_Inline}}
33+
- : Always returns `"layout-shift"`.
34+
- {{domxref("PerformanceEntry.startTime")}} {{ReadOnlyInline}} {{Experimental_Inline}}
35+
- : Returns a {{domxref("DOMHighResTimeStamp")}} representing the time when the layout shift started.
36+
37+
This interface also supports the following properties:
38+
1839
- {{domxref("LayoutShift.value")}} {{Experimental_Inline}}
19-
- : Returns the `impact fraction` (fraction of the viewport that was shifted) times the `distance fraction` (distance moved as a fraction of viewport).
40+
- : Returns the layout shift score calculated as the impact fraction (fraction of the viewport that was shifted) multiplied by the distance fraction (distance moved as a fraction of viewport).
2041
- {{domxref("LayoutShift.hadRecentInput")}} {{Experimental_Inline}}
21-
- : Returns `true` if there was a user input in the past 500 milliseconds.
42+
- : Returns `true` if {{domxref("LayoutShift.lastInputTime", "lastInputTime")}} is less than 500 milliseconds in the past.
2243
- {{domxref("LayoutShift.lastInputTime")}} {{Experimental_Inline}}
23-
- : Returns the time of the most recent user input.
44+
- : Returns the time of the most recent excluding input (user input that would exclude this entry as a contributor to the CLS score) or `0` if no excluding input has occurred.
2445
- {{domxref("LayoutShift.sources")}} {{Experimental_Inline}}
25-
- : Returns an array of {{domxref('LayoutShiftAttribution')}} objects with information on the elements that were shifted.
46+
- : Returns an array of {{domxref("LayoutShiftAttribution")}} objects with information on the elements that were shifted.
2647

2748
## Instance methods
2849

@@ -31,39 +52,28 @@ The `LayoutShift` interface of the [Layout Instability API](/en-US/docs/Web/API/
3152

3253
## Examples
3354

34-
The following example shows how to capture layout shifts and log them to the console.
55+
### Logging layout shift values
3556

36-
Note that in this example data is only sent to the server when the user leaves the tab.
57+
The following example shows how to capture layout shifts and log them to the console.
3758

3859
```js
39-
// Catch errors since some browsers throw when using the new `type` option.
40-
// https://webkit.org/b/209216
41-
try {
42-
let cumulativeLayoutShiftScore = 0;
43-
44-
const observer = new PerformanceObserver((list) => {
45-
for (const entry of list.getEntries()) {
46-
// Only count layout shifts without recent user input.
47-
if (!entry.hadRecentInput) {
48-
cumulativeLayoutShiftScore += entry.value;
60+
const observer = new PerformanceObserver((list) => {
61+
for (const entry of list.getEntries()) {
62+
// Count layout shifts without recent user input only
63+
if (!entry.hadRecentInput) {
64+
console.log("LayoutShift value:", entry.value);
65+
if (entry.sources) {
66+
for (const { node, currentRect, previousRect } of entry.sources)
67+
console.log("LayoutShift source:", node, {
68+
currentRect,
69+
previousRect,
70+
});
4971
}
5072
}
51-
});
52-
53-
observer.observe({ type: "layout-shift", buffered: true });
54-
55-
document.addEventListener("visibilitychange", () => {
56-
if (document.visibilityState === "hidden") {
57-
// Force any pending records to be dispatched.
58-
observer.takeRecords();
59-
observer.disconnect();
73+
}
74+
});
6075

61-
console.log("CLS:", cumulativeLayoutShiftScore);
62-
}
63-
});
64-
} catch (e) {
65-
// Do nothing if the browser doesn't support this API.
66-
}
76+
observer.observe({ type: "layout-shift", buffered: true });
6777
```
6878

6979
## Specifications
@@ -73,3 +83,8 @@ try {
7383
## Browser compatibility
7484

7585
{{Compat}}
86+
87+
## See also
88+
89+
- {{domxref("LayoutShiftAttribution")}}
90+
- [Cumulative Layout Shift (CLS)](https://web.dev/cls/)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
title: LayoutShift.lastInputTime
3+
slug: Web/API/LayoutShift/lastInputTime
4+
page-type: web-api-instance-property
5+
browser-compat: api.LayoutShift.lastInputTime
6+
status:
7+
- experimental
8+
---
9+
10+
{{SeeCompatTable}}{{APIRef("Performance API")}}
11+
12+
The **`lastInputTime`** read-only property of the {{domxref("LayoutShift")}} interface returns the time of the most recent excluding input or `0` if no excluding input has occurred.
13+
14+
Layout shifts are only bad if the user wasn't expecting them. Many layout shift metrics (like [Cumulative Layout Shift (CLS)](https://web.dev/cls/)) exclude shifts that occurred soon after certain user interactions. These interactions are called _excluding inputs_. Excluding inputs are:
15+
16+
- Any events which signal a user's active interaction with the document: ([`mousedown`](/en-US/docs/Web/API/Element/mousedown_event), [`keydown`](/en-US/docs/Web/API/Element/keydown_event), and [`pointerdown`](/en-US/docs/Web/API/Element/pointerdown_event))
17+
- Any events which directly changes the size of the viewport.
18+
- [`change`](/en-US/docs/Web/API/HTMLElement/change_event) events.
19+
20+
The [`mousemove`](/en-US/docs/Web/API/Element/mousemove_event) and [`pointermove`](/en-US/docs/Web/API/Element/pointermove_event) events are **not** excluding inputs.
21+
22+
## Value
23+
24+
A {{domxref("DOMHighResTimeStamp")}} indicating the most recent excluding input time or `0` if no excluding input has occurred.
25+
26+
## Examples
27+
28+
### Logging last input times
29+
30+
Log excluding input times if excluding input has occurred.
31+
32+
```js
33+
const observer = new PerformanceObserver((list) => {
34+
list.getEntries().forEach((entry) => {
35+
if (entry.lastInputTime) {
36+
console.log(entry.lastInputTime);
37+
}
38+
});
39+
});
40+
41+
observer.observe({ type: "layout-shift", buffered: true });
42+
```
43+
44+
## Specifications
45+
46+
{{Specifications}}
47+
48+
## Browser compatibility
49+
50+
{{Compat}}
51+
52+
## See also
53+
54+
- {{domxref("LayoutShift.hadRecentInput")}}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
title: LayoutShift.sources
3+
slug: Web/API/LayoutShift/sources
4+
page-type: web-api-instance-property
5+
browser-compat: api.LayoutShift.sources
6+
status:
7+
- experimental
8+
---
9+
10+
{{SeeCompatTable}}{{APIRef("Performance API")}}
11+
12+
The **`sources`** read-only property of the {{domxref("LayoutShift")}} interface returns an array of {{domxref("LayoutShiftAttribution")}} objects that indicate the DOM elements that moved during the layout shift.
13+
14+
## Value
15+
16+
An {{jsxref("Array")}} of {{domxref("LayoutShiftAttribution")}} objects. This array will not contain more than five sources. If there are more than five elements impacted by the layout shift, the five most impactful elements are reported.
17+
18+
## Examples
19+
20+
### Logging layout shift sources
21+
22+
```js
23+
const observer = new PerformanceObserver((list) => {
24+
list.getEntries().forEach((entry) => {
25+
entry.sources.forEach((source) => {
26+
console.log(source);
27+
});
28+
});
29+
});
30+
31+
observer.observe({ type: "layout-shift", buffered: true });
32+
```
33+
34+
## Specifications
35+
36+
{{Specifications}}
37+
38+
## Browser compatibility
39+
40+
{{Compat}}
41+
42+
## See also
43+
44+
- {{domxref("LayoutShiftAttribution")}}

0 commit comments

Comments
 (0)