1. Introduction
This section is non-normative.
The shifting of DOM elements on a webpage detracts from the user’s experience, and occurs frequently on the web today. This shifting is often due to content loading asynchronously and displacing other elements on the page.
The layout Instability API identifies these unstable pages by reporting a value (the "layout shift") for each animation frame in the user’s session. This specification presents a method for a user agent to compute the layout shift value.
The layout shift value is expected to have a general correspondence to the severity of layout instability at a particular time. The method of computing it considers both the area of the region impacted by instability and the distance by which elements on the page are shifted.
The developer can use the layout shift values that are reported by this API to compute a cumulative score (the "cumulative layout shift score").
The cumulative layout shift score is expected to have a general correspondence to the severity of layout instability for the lifetime of a page.
1.1. End of session signal
This section is non-normative.
The developer can compute a cumulative layout shift score by summing the layout shift values as they are reported to the observer.
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 strategy is illustrated in the usage example.
1.2. Usage example
This section is non-normative.
// Stores the current layout shift score for the page. let cumulativeLayoutShiftScore= 0 ; // Detects new layout shift occurrences and updates the // `cumulativeLayoutShiftScore` variable. const observer= new PerformanceObserver(( list) => { for ( const entryof list. getEntries()) { // Only count layout shifts without recent user input. if ( ! entry. hadRecentInput) { cumulativeLayoutShiftScore+= entry. value; } } }); observer. observe({ type: 'layout-shift' , buffered: true }); // Sends the final score to your analytics back end once // the page’s lifecycle state becomes hidden. document. addEventListener( 'visibilitychange' , () => { if ( document. visibilityState=== 'hidden' ) { // Force any pending records to be dispatched. observer. takeRecords(); // Send the final score to your analytics back end // (assumes `sendToAnalytics` is defined elsewhere). sendToAnalytics({ cumulativeLayoutShiftScore}); } });
The layout shift score is only one signal, which correlates in an approximate manner with the user experience of "jumpiness".
Developers should 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.
2. Terminology
2.1. Basic Concepts
The starting point of a Node
N in a coordinate space C is defined as follows:
-
If N is an
Element
which generates one or more boxes, the starting point of N in C is the two-dimensional offset in pixel units from the origin of C to the flow-relative starting corner of the first fragment of the principal box of N. -
If N is a text node, the starting point of N in C is the two-dimensional offset in pixel units from the origin of C to the flow-relative starting corner of the first line box generated by N.
The visual representation of a Node
N is defined as
follows:
-
If N is an
Element
which generates one or more boxes, the visual representation of N is the set of all points that lie within the bounds of any fragment of any box generated by N, in the coordinate space of the viewport, excluding any points that lie outside of the viewport. -
If N is a text node, the visual representation of N is the set of all points that lie within the bounds of any line box generated by N, in the coordinate space of the viewport, excluding any points that lie outside of the viewport.
A condition holds in the previous frame if it was true at the point in time immediately after the most recently completed invocation of the report the layout shift algorithm.
The previous frame starting point of a Node
N in a
coordinate space C is the point which, in the previous frame, was the starting point of N in C.
The previous frame visual representation of a Node
N is
the set which, in the previous frame, was the visual
representation of N.
2.2. Unstable Nodes
A Node
N has shifted in a coordinate space C if the starting point of N in C differs from the previous frame starting
point of N in C by 3 or more pixel units in either the horizontal
or vertical direction.
Otherwise, N has not shifted in C.
A Node
N is unstable if:
-
N is either
-
N has shifted in the coordinate space of the viewport; and
-
N has shifted in the coordinate space of the initial containing block; and
-
there does not exist an
Element
P such that-
currently and in the previous frame, P is in the containing block chain of N, and
-
currently and in the previous frame, P has a local coordinate system or a scrollable overflow region, and
-
P is not unstable, and
-
N has not shifted in the coordinate space of the local coordinate system or scrollable overflow region of P.
-
The unstable node set of a Document
D is the set
containing every unstable shadow-including descendant of D.
NOTE: In the first frame, the previous frame starting point does not exist for any node, and therefore the unstable node set is empty.
2.3. Layout Shift Value
The viewport base distance is the greater of the visual viewport width or the visual viewport height.
The move vector of a Node
N is the two-dimensional
offset in pixel units from
-
the previous frame starting point of N in the coordinate space of the viewport, to
-
the starting point of N in the coordinate space of the viewport.
The move distance of a Node
N is the greater of
-
the absolute value of the horizontal component of the move vector of N, or
-
the absolute value of the vertical component of the move vector of N.
The maximum move distance of a Document
D is the
greatest move distance of any Node
in the unstable node set of D, or 0 if the unstable node set of D is empty.
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.
The impact region of a Document
D is the set containing
-
every point in the visual representation of any
Node
in the unstable node set of D, and -
every point in the previous frame visual representation of any
Node
in the unstable node set of D.
The impact fraction of a Document
D is the area of the impact region divided by the area of the viewport.
The layout shift value of a Document
D is the impact
fraction of D multiplied by the distance fraction of D.
NOTE: The layout shift value takes into account both the fraction of the viewport that has been impacted by layout instability as well as the greatest distance by which any given element has moved. This recognizes that a large element which moves only a small distance can have a low impact on the perceived instability of the page.
2.4. Input Exclusion
An excluding input is any event from an input device which signals a user’s active interaction with the document, or any event which directly changes the size of the viewport.
Excluding inputs generally include mousedown, keydown, and pointerdown. However, an event whose only effect is to begin or update a fling or scroll gesture is not an excluding input.
The user agent may delay the reporting of layout shifts after a pointerdown event until such time as it is known that the event does not begin a fling or scroll gesture.
The mousemove and pointermove events are also not excluding inputs.
3. LayoutShift
interface
[Exposed =Window ]interface :
LayoutShift PerformanceEntry {readonly attribute long value ;readonly attribute boolean hadRecentInput ;readonly attribute DOMHighResTimeStamp lastInputTime ; [Default ]object (); };
toJSON
All attributes have the values which are assigned to them by the steps to report the layout shift.
A user agent implementing the Layout Instability API MUST include
in supportedEntryTypes
for Window contexts. This allows developers to detect support for the Layout Instability API.
4. Processing model
Within the update the rendering step of the event loop processing model, a user agent implementing the Layout Instability API MUST perform the following step after the step that invokes the mark paint timing algorithm:
-
For each fully active
Document
in docs, invoke the algorithm to report the layout shift for thatDocument
.
4.1. Report the layout shift
Document
D, run the following steps:
-
If the current layout shift value of D is not 0:
-
Create a new
LayoutShift
object newEntry. -
Set newEntry’s
name
attribute to
."layout-shift" -
Set newEntry’s
entryType
attribute to
."layout-shift" -
Set newEntry’s
startTime
attribute to current high resolution time. -
Set newEntry’s
duration
attribute to 0. -
Set newEntry’s
value
attribute to the current layout shift value of D. -
Set newEntry’s
lastInputTime
attribute to the time of the most recent excluding input, or 0 if no excluding input has occurred during the browsing session. -
Set newEntry’s
hadRecentInput
attribute to
iftrue lastInputTime
is less than 500 milliseconds in the past, and
otherwise.false -
Queue the PerformanceEntry newEntry object.
-
5. Security & privacy considerations
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 instability in the current browsing context. It does not directly provide any aggregation of instability scores across multiple browsing contexts. Developers can implement such aggregation manually, but browsing contexts with different origins would need to cooperate to share instability scores.