• Stars
    star
    158
  • Rank 237,131 (Top 5 %)
  • Language Makefile
  • License
    Other
  • Created over 5 years ago
  • Updated 10 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A proposal for a Layout Instability specification

Explainer: Layout Instability Metric

Overview

Many websites suffer from layout instability - DOM elements shifting around due to content loading asynchronously.

We propose a way for the user agent to measure layout instability during a browsing session to compute "layout shift scores", which would be exposed by a new interface in the Performance API.

Layout Shift Score

Each animation frame (a.k.a. "rendering update") computes a layout shift (LS) score approximating the severity of visible layout instability in the document during that frame. An animation frame with no layout instability has an LS score of 0. Higher LS scores correspond to greater instability.

The LS score is based on a set of shifting nodes and two intermediate values, the impact fraction and the distance fraction.

Shifting Nodes

A shifting node is a DOM node whose visual representation starts in a different location than it did in the previous animation frame for a reason other than transform change or scrolling.

"Starts" refers here to the node's flow-relative offset - for example, its top left corner in a horizontal left-to-right writing mode.

The visual representation of a node is the space occupied by its box fragments (for elements) or line boxes (for text nodes).

Note that:

  • A node that changes in size (for example, by having children appended), but starts at the same offset, is not a shifting node.

  • A node whose start location changes two or more times during the same animation frame (for example, from forced synchronous layouts), but is ultimately painted at the same location as the previous frame, is not a shifting node.

Transform Changes

Changing an element's transform affects its visual representation. However, because

  • transform changes don't reflow surrounding content,
  • transform changes are a common target of fluid animations, and
  • animated transform changes are easily rendered with hardware-accelerated compositing on a separate thread from the browser's layout and script execution tasks,

the layout instability metric doesn't treat transform-changing elements, or their descendants, as shifting elements (unless their layout is affected in some other way at the same time).

Scrolling

To be a shifting node, the start location must change relative to the document origin, the viewport, and every containing scrollable area. This ensures that

  • scrolling a simple element doesn't produce a layout shift (though this changes its location relative to the viewport);

  • scrolling with a position: fixed element doesn't produce a layout shift (though this changes the fixed element's location relative to the document origin); and

  • scrolling an overflow: scroll container doesn't produce a layout shift (though this changes the locations of descendant elements relative to both the viewport and the document origin).

Impact Fraction

The impact region of an animation frame is the geometric union of the previous-frame and current-frame visual representations, intersected with the viewport, of all shifting nodes in that frame.

The impact fraction of an animation frame is the fraction of the viewport that is occupied by the impact region.

Illustration of a shifting element on a device, with the impact region highlighted

Example: An element which occupies half the viewport shifts by a distance equal to half its height. The impact fraction for this animation frame is 0.75.

Distance Fraction

The move distance of a shifting node is the distance it has moved on the horizontal or vertical axis (whichever is greater), relative to the viewport.

The distance fraction of an animation frame is the greatest move distance of any shifting node in that frame, divided by the width or height (whichever is greater) of the viewport.

Illustration of shifting elements on a device, with their move distances indicated by arrows

Example: The most-shifted element moved a distance of one quarter of the viewport. The distance fraction for this animation frame is 0.25.

The intent of incorporating the distance fraction into the LS score calculation is to avoid overly penalizing cases where large elements shift by small distances.

LS Score Calculation

The layout shift (LS) score is equal to the impact fraction multiplied by the distance fraction.

Performance API

Animation frames with non-zero LS scores will notify a registered PerformanceObserver. The observer's callback receives one or more LayoutShift entries:

interface LayoutShift : PerformanceEntry {
    double value;
    boolean hadRecentInput;
    DOMHighResTimeStamp lastInputTime;
    sequence<LayoutShiftAttribution> sources;
};

The entry's value attribute is the LS score. Its entryType attribute is "layout-shift".

The hadRecentInput and lastInputTime attributes are described in Recent Input Exclusion.

The sources attribute is described in Source Attribution.

Cumulative Scores

The user agent can compute a document cumulative layout shift (DCLS) score as the sum of the document's LS scores for each animation frame that has occurred during the browsing session. The DCLS score is 0 when the document begins loading, and grows whenever layout instability occurs. The DCLS score does not account for layout instability inside descendant browsing contexts, such as those created by <iframe> elements.

The user agent can compute a cumulative layout shift (CLS) score for a top-level browsing context by summing the LS scores of the top-level browsing context to the weighted LS scores of its descendant browsing contexts. In performing this aggregation, the LS score of a layout shift in an <iframe> should be weighted by the fraction of the top-level viewport the <iframe> occupies at the time the layout shift occurs.

The DCLS and CLS scores are not directly exposed by the Performance API, but we hope to make it easy for developers to construct these from the LS scores.

Recent Input Exclusion

In calculating DCLS and CLS scores, developers and user agents may wish to exclude LS scores from animation frames that occur after recent UI events events such as taps, key presses, and mouse clicks. This allows the page to modify its layout in response to the event.

To facilitate this exclusion, the LayoutShift entry has attributes indicating when such input last occurred, and whether it should be considered "recent" for the purpose of the exclusion.

The hadRecentInput attribute is true when the last input occurred within the past 500 ms. It should be treated as a hint to ignore the layout shift in calculating the DCLS and CLS scores. This threshold was chosen to allow the page to make asynchronous rendering updates as a result of the input, as long as they occur without excessive delay. Developers wishing to implement a different threshold can do so by examining the lastInputTime.

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.

Source Attribution

NOTE: The sources attribute is currently only available in Chrome 84+ with "Experimental Web Platform features" enabled (chrome://flags).

On a complex website, it can be difficult to understand the cause of a high CLS score given only the numeric values in the value attribute of the LayoutShift entries.

To aid that effort, the sources attribute connects the LayoutShift back to the specific DOM elements that experienced the shift. This gives the developer more insight into the causes of layout instability on their site.

The sources attribute is an array of up to 5 LayoutShiftAttribution objects:

interface LayoutShiftAttribution {
    Node node;
    DOMRect previousRect;
    DOMRect currentRect;
};

Each attribution contains a reference to a shifted DOM node along with rects that describe its visual representation in the viewport before and after the shift.

Prioritization by Impact

Many nodes may shift in a single animation frame, but the user agent selects no more than 5 to attribute in sources, and tries to avoid redundancy. The method of selection follows these principles:

  • If two nodes have shifted, and one fully contains the other (visually), only the larger node is attributed. This means for example that if a container node shifts, we would not generally need to attribute all of its descendants, even though they too have shifted.

  • If, after the elimination described above, there are still more than 5 shifted nodes eligible for attribution, they are prioritized by the size of their contribution to the impact region. That is, nodes occupying a greater area within the viewport are preferred.

We limit the number of attributions to 5 for the following reasons:

  • In a large DOM, many nodes may shift at once, and it may be infeasible for user agents to report the full set of shifted nodes in a performant way.

  • It may be cumbersome for developers to receive the full set of shifted nodes, and would encourage them to write non-performant code to examine such a set.

  • Given the hierarchical nature of DOM, surfacing a small number of high level shifted elements is usually sufficient to understand the cause of layout instability. Limiting to 5 with prioritization improves the signal to noise ratio of the report.

Caveat: Causality

It is possible that the true "root cause" of instability will be only indirectly related to the DOM element that experiences a layout shift. For example, if a newly inserted element shifts content below it, the sources attribute will report only the shifted elements, and not the inserted element.

We do not believe it is feasible for the user agent to understand causes of instability at the level of indirection necessary for a meaningful "root cause" attribution. However, we expect that the more straightforward reporting of shifted elements in sources will nevertheless be of significant value to developers who are attempting to diagnose an occurrence of layout instability.

Specification

The updates to the Layout Instability API specification to incorporate and explain the sources attribute are tracked in issue #11.

Computing DCLS with the API

The developer can compute the DCLS score by summing the LS scores:

addEventListener("load", () => {
    let DCLS = 0;
    new PerformanceObserver((list) => {
        list.getEntries().forEach((entry) => {
            if (entry.hadRecentInput)
                return;  // Ignore shifts after recent input.
            DCLS += entry.value;
        });
    }).observe({type: "layout-shift", buffered: true});
});

By passing buffered: true to observe, the observer is immediately notified of any layout shifts that occurred before it was registered. (Layout shift entries are not available from the Performance Timeline through getEntriesByType.)

A "final" DCLS score for the user's session can be reported by listening to the visibilitychange event, and using the value of DCLS at that time.

A demo page illustrating the use of this code can be viewed in Chrome 76+ with the command-line flag --enable-blink-features=LayoutInstabilityAPI, or in Chrome 73-75 with the command-line flag --enable-blink-features=LayoutJankAPI.

Limitations

The presence of "layout instability" as defined by this metric correlates imperfectly with the user experience of "jumpy" websites.

It's possible for a website to seem jumpy, but score well on CLS. For example, rebuilding the DOM with entirely new elements does not trigger a layout shift.

Conversely, it's possible for a website to provide a smooth user experience, but score poorly on CLS. For example, an image carousel that animates a layout property such as left will produce a layout shift on every frame of the animation. (Carousel authors should use transform instead, which avoids the layout shift, and also enables off-thread accelerated compositing.)

The metric tries to make some allowances (transform changes, recent input) for visual updates that are not likely to negatively impact the user experience. But these are in essence heuristics, and not guaranteed to work well in every case.

Precision, Variance, and Evolution

We provide a reasonably precise method of computing scores for layout instability, but the score remains an approximation of the user experience.

We expect developers to use the score as a signal, and not to rely on its exact numeric value in a manner such that the correctness of their page would be impacted by a minor deviation in it.

The user agent may trade off precision for efficiency in the computation of LS scores. It is intended that the LS score have a correspondence to the perceptual severity of the instability, but not that all user agents produce exactly the same LS scores for a given page.

We expect the definition of the layout instability metric to evolve over time; it should not be considered "frozen" merely because a spec has been produced.

We hope that such evolution can occur with sufficient cooperation between implementers, so that browsers do not vary so significantly that developers must choose between optimizing for one implementation over another.

Privacy and Security

Layout instability bears an indirect relationship to resource timing, as slow resources could cause intermediate layouts that would not otherwise be performed. Resource timing information can be used by malicious websites for statistical fingerprinting.

The layout instability API only reports layout shifts in the current browsing context (frame). It does not directly provide the CLS score incorporating subframes. Developers can implement such aggregation manually, but browsing contexts with different origins would need to cooperate to share LS scores.

Terminology

The "layout instability metric" was previously called the "layout stability metric".

"Layout instability" and "layout shift" were previously referred to as "layout jank". The impact region was previously referred to as the "jank region". The LS score was previously referred to as the "jank fraction".

The DCLS score and CLS score were previously referred to as "(aggregate) jank score".

The LayoutShift interface was previously implemented as PerformanceLayoutJank. Its "value" attribute was previously named "fraction", and its entryType was previously "layoutJank".

The layout instability API is an extension of the web performance API, but it is not related to the speed or timing of layout computation.

Links

More Repositories

1

webcomponents

Web Components specifications
HTML
4,360
star
2

import-maps

How to control the behavior of JavaScript imports
JavaScript
2,705
star
3

virtual-scroller

1,998
star
4

focus-visible

Polyfill for `:focus-visible`
JavaScript
1,607
star
5

webusb

Connecting hardware to the web.
Bikeshed
1,310
star
6

webpackage

Web packaging format
Go
1,231
star
7

EventListenerOptions

An extension to the DOM event pattern to allow authors to disable support for preventDefault
JavaScript
1,166
star
8

portals

A proposal for enabling seamless navigations between sites or pages
HTML
946
star
9

floc

This proposal has been replaced by the Topics API.
Makefile
934
star
10

inert

Polyfill for the inert attribute and property.
JavaScript
920
star
11

scheduling-apis

APIs for scheduling and controlling prioritized tasks.
HTML
909
star
12

view-transitions

811
star
13

file-system-access

Expose the file system on the user’s device, so Web apps can interoperate with the user’s native applications.
Bikeshed
658
star
14

background-sync

A design and spec for ServiceWorker-based background synchronization
HTML
639
star
15

ua-client-hints

Wouldn't it be nice if `User-Agent` was a (set of) client hints?
Bikeshed
590
star
16

scroll-to-text-fragment

Proposal to allow specifying a text snippet in a URL fragment
HTML
586
star
17

observable

Observable API proposal
Bikeshed
582
star
18

aom

Accessibility Object Model
HTML
567
star
19

kv-storage

[On hold] A proposal for an async key/value storage API for the web
550
star
20

turtledove

TURTLEDOVE
Bikeshed
526
star
21

navigation-api

The new navigation API provides a new interface for navigations and session history, with a focus on single-page application navigations.
Makefile
486
star
22

webmonetization

Proposed Web Monetization standard
HTML
461
star
23

trust-token-api

Trust Token API
Bikeshed
421
star
24

attribution-reporting-api

Attribution Reporting API
Bikeshed
360
star
25

direct-sockets

Direct Sockets API for the web platform
HTML
329
star
26

shape-detection-api

Detection of shapes (faces, QR codes) in images
Bikeshed
304
star
27

display-locking

A repository for the Display Locking spec
HTML
297
star
28

dbsc

Bikeshed
297
star
29

background-fetch

API proposal for background downloading/uploading
Shell
281
star
30

first-party-sets

Bikeshed
280
star
31

serial

Serial ports API for the platform.
HTML
256
star
32

resize-observer

This repository is no longer active. ResizeObserver has moved out of WICG into
HTML
255
star
33

priority-hints

A browser API to enable developers signal the priorities of the resources they need to download.
Bikeshed
249
star
34

sanitizer-api

Bikeshed
227
star
35

is-input-pending

HTML
221
star
36

proposals

A home for well-formed proposed incubations for the web platform. All proposals welcome.
216
star
37

spatial-navigation

Directional focus navigation with arrow keys
JavaScript
212
star
38

js-self-profiling

Proposal for a programmable JS profiling API for collecting JS profiles from real end-user environments
HTML
197
star
39

cq-usecases

Use cases and requirements for standardizing element queries.
HTML
184
star
40

isolated-web-apps

Repository for explainers and other documents related to the Isolated Web Apps proposal.
Bikeshed
182
star
41

visual-viewport

A proposal to add explicit APIs to the Web for querying and setting the visual viewport
HTML
177
star
42

interventions

A place for browsers and web developers to collaborate on user agent interventions.
176
star
43

frame-timing

Frame Timing API
HTML
170
star
44

page-lifecycle

Lifecycle API to support system initiated discarding and freezing
HTML
154
star
45

nav-speculation

Proposal to enable privacy-enhanced preloading
HTML
154
star
46

speech-api

Web Speech API
Bikeshed
145
star
47

cookie-store

Asynchronous access to cookies from JavaScript
Bikeshed
143
star
48

construct-stylesheets

API for constructing CSS stylesheet objects
Bikeshed
137
star
49

webhid

Web API for accessing Human Interface Devices (HID)
HTML
137
star
50

color-api

A proposal and draft spec for a Color object for the Web Platform, loosely influenced by the Color.js work. Heavily WIP, if you landed here randomly, please move along.
HTML
132
star
51

fenced-frame

Proposal for a strong boundary between a page and its embedded content
Bikeshed
126
star
52

devtools-protocol

DevTools Protocol
JavaScript
120
star
53

sms-one-time-codes

A way to format SMS messages for use with browser autofill features such as HTML’s autocomplete=one-time-code.
Makefile
111
star
54

bundle-preloading

Bundles of multiple resources, to improve loading JS and the Web.
HTML
105
star
55

translation-api

A proposal for translator and language detector APIs
Bikeshed
104
star
56

privacy-preserving-ads

Privacy-Preserving Ads
HCL
100
star
57

manifest-incubations

Before install prompt API for installing web applications
HTML
99
star
58

window-controls-overlay

HTML
97
star
59

netinfo

HTML
95
star
60

compression-dictionary-transport

94
star
61

intrinsicsize-attribute

Proposal to add an intrinsicsize attribute to media elements
93
star
62

animation-worklet

🚫 Old repository for AnimationWorklet specification ➑️ New repository: https://github.com/w3c/css-houdini-drafts
Makefile
92
star
63

container-queries

HTML
91
star
64

local-peer-to-peer

↔️ Proposal for local communication between browsers without the aid of a server.
Bikeshed
90
star
65

shared-storage

Explainer for proposed web platform Shared Storage API
Bikeshed
89
star
66

async-append

A way to create DOM and add it to the document without blocking the main thread.
HTML
87
star
67

indexed-db-observers

Prototyping and discussion around indexeddb observers.
WebIDL
84
star
68

canvas-formatted-text

HTML
82
star
69

file-handling

API for web applications to handle files
82
star
70

canvas-color-space

Proposed web platform feature to add color management, wide gamut and high bit-depth support to the <canvas> element.
79
star
71

local-font-access

Web API for enumerating fonts on the local system
Bikeshed
77
star
72

performance-measure-memory

performance.measureMemory API
HTML
77
star
73

digital-credentials

Digital Credentials, like driver's licenses
HTML
77
star
74

handwriting-recognition

Handwriting Recognition Web API Proposal
Bikeshed
75
star
75

web-app-launch

Web App Launch Handler
HTML
75
star
76

pwa-url-handler

72
star
77

ContentPerformancePolicy

A set of policies that a site guarantees to adhere to, browsers enforce, and embedders can count on.
HTML
72
star
78

starter-kit

A simple starter kit for incubations
JavaScript
72
star
79

css-parser-api

This is the repo where the CSS Houdini parser API will be worked on
HTML
71
star
80

close-watcher

A web API proposal for watching for close requests (e.g. Esc, Android back button, ...)
Makefile
71
star
81

eyedropper-api

HTML
69
star
82

idle-detection

A proposal for an idle detection and notification API for the web
Bikeshed
67
star
83

storage-foundation-api-explainer

Explainer showcasing a new web storage API, NativeIO
65
star
84

video-editing

65
star
85

uuid

UUID V4
63
star
86

client-hints-infrastructure

Specification for the Client Hints infrastructure - privacy preserving proactive content negotiation
Bikeshed
61
star
87

sparrow

60
star
88

private-network-access

HTML
58
star
89

element-timing

A proposal for an Element Timing specification.
Bikeshed
57
star
90

document-picture-in-picture

Bikeshed
56
star
91

video-rvfc

video.requestVideoFrameCallback() incubation
HTML
53
star
92

time-to-interactive

Repository for hosting TTI specification and discussions around it.
52
star
93

digital-goods

Bikeshed
50
star
94

soft-navigations

Heuristics to detect Single Page Apps soft navigations
Bikeshed
46
star
95

raw-clipboard-access

An explainer for the Raw Clipboard Access feature
44
star
96

storage-buckets

API proposal for managing multiple storage buckets
Bikeshed
43
star
97

pending-beacon

A better beaconing API
Bikeshed
43
star
98

admin

πŸ‘‹ Ask your questions here! πŸ‘‹
HTML
42
star
99

web-smart-card

Repository for the Web Smart Card Explainer
HTML
42
star
100

web-preferences-api

The Web Preference API aims to provide a way for sites to override the value for a given user preference (e.g. color-scheme preference) in a way that fully integrates with existing Web APIs.
Bikeshed
41
star