Paint Timing

W3C Working Draft,

More details about this document
This version:
https://www.w3.org/TR/2024/WD-paint-timing-20241112/
Latest published version:
https://www.w3.org/TR/paint-timing/
Editor's Draft:
https://w3c.github.io/paint-timing/
Previous Versions:
History:
https://www.w3.org/standards/history/paint-timing/
Feedback:
GitHub
Inline In Spec
Editors:
(Google)
(Invited Expert)
Former Editors:
(Google)
(Google)

Abstract

This document defines an API that can be used to capture a series of key moments (first paint, first contentful paint) during pageload which developers care about.

Status of this document

This section describes the status of this document at the time of its publication. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at https://www.w3.org/TR/.

This document was published by the Web Performance Working Group as a Working Draft using the Recommendation track. Publication as a Working Draft does not imply endorsement by W3C and its Members.

This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

GitHub Issues are preferred for discussion of this specification.

This document is governed by the 03 November 2023 W3C Process Document.

This document was produced by a group operating under the W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

1. Introduction

This section is non-normative.

Much of the purpose of a web browser is to translate HTML, CSS and image resources into pixels on a screen for users. Measuring the performance of a web page often involves measuring the time it takes to perform these tasks - to render content, whether text or image, to the screen. There are many different ways to use this timing to make statemements about the performance of a page, or about the user experience of loading, but fundamentally all of those ways begin with a common means of measuring time.

This is a foundational document which specifies how to measure paint timing as a general-purpose mechanism. That foundation is then used to define the First Paint and First Contentful Paint metrics. Other specific instances of paint measurement may be specified in other documents.

Specifically, this specification covers:

1.1. First Paint and First Contentful Paint

Load is not a single moment in time — it’s an experience that no one metric can fully capture. There are multiple moments during the load experience that can affect whether a user perceives it as "fast" or "slow".

First paint (FP) is the first of these key moments, followed by first contentful paint (FCP). These metrics mark the points in time when the browser renders a given document. This is important to the user because it answers the question: is it happening?

The primary difference between the two metrics is FP marks the first time the browser renders anything for a given document. By contrast, FCP marks the time when the browser renders the first bit of image or text content from the DOM.

1.2. Usage example

const observer = new PerformanceObserver(function(list) {
    const perfEntries = list.getEntries();
    for (const perfEntry of perfEntries) {
        // Process entries
        // report back for analytics and monitoring
        // ...
    }
});

// register observer for paint timing notifications
observer.observe({entryTypes: ["paint"]});

2. Terminology

Paint: the user agent has performed a "paint" (or "render") when it has converted the render tree to pixels on the screen. Formally, we consider the user agent to have "rendered" a document when it has performed the update the rendering steps of the event loop.

NOTE: The rendering pipeline is very complex, and the timestamp should be the latest timestamp the user agent is able to note in this pipeline (best effort). Typically the time at which the frame is submitted to the OS for display is recommended for this API.

A generated content pseudo-element is a paintable pseudo-element when all of the following apply:

A CSS image img is a contentful image when all of the following apply:

A DOMString is non-empty if it contains at least one character excluding document white space characters.

An element target is contentful when one or more of the following apply:

An element is timing-eligible if it is one of the following:

To compute the paintable bounding rect of element target, run the following steps:

  1. Let boundingRect be the result of running the getBoundingClientRect() on target.

  2. Clip boundingRect with the document's scrolling area.

  3. Return boundingRect.

NOTE: elements contained by boxes with overflow: scroll or overflow: hidden don’t have their paintable bounding rect clipped, as in both cases the element can become visible by scrolling.

An element el is paintable when all of the following apply:

First paint entry contains a DOMHighResTimeStamp reporting the time when the user agent first rendered after navigation. This excludes the default background paint, but includes non-default background paint and the enclosing box of an iframe. This is the first key moment developers care about in page load – when the user agent has started to render the page.

A browsing context ctx is paint-timing eligible when one of the following apply:

The PaintTimingMixin interface {#sec-PaintTimingMixin}

[Exposed=Window]
interface mixin PaintTimingMixin {
    readonly attribute DOMHighResTimeStamp paintTime;
    readonly attribute DOMHighResTimeStamp? presentationTime;
};

Objects including the PaintTimingMixin interface mixin have an associated paint timing info (null or a paint timing info).

paint timing info is a struct. It has the following items:

rendering update end time

A DOMHighResTimeStamp

implementation-defined presentation time

Null or a DOMHighResTimeStamp

The paintTime attribute’s getter step is to return this's paint timing info's rendering update end time.

The presentationTime attribute’s getter step, if exists, is to return this's paint timing info's implementation-defined presentation time.

To get the default paint timestamp for a paint timing info paintTimingInfo, return paintTimingInfo’s implementation-defined presentation time if it is non-null, otherwise paintTimingInfo’s rendering update end time.

3. The PerformancePaintTiming interface

[Exposed=Window]
interface PerformancePaintTiming : PerformanceEntry {};
PerformancePaintTiming includes PaintTimingMixin;

PerformancePaintTiming extends the following attributes of PerformanceEntry interface:

NOTE: A user agent implementing PerformancePaintTiming would need to include "paint" in supportedEntryTypes of a global object whose browsing context is paint-timing eligible. This allows developers to detect support for paint timing for a particular browsing context.

4. Processing model

4.1. Associated Image Requests

Each Element has an associated image request which is an image request or null, initially null.

When the processing model for an Element element of type HTMLImageElement, SVGImageElement, or HTMLVideoElement creates a new image resource (e.g., to be displayed as an image or poster image), element’s associated image request is set to the image request of the created image resource.

Note: Every image resource that is obtained from a URL whose scheme is equal to "data" has an associated image request which is not fetched but still needs to be loaded. This request can be the associated image request of an Element.

Note: The current language is vague since it does not point to specific algorithms. This can be made more rigorous when the corresponding processing models have a more unified processing model.

Every Element has a list of associated background image requests which is initially an empty array. When the processing model for the Element element’s style requires a new image resource (to be displayed as background image), the image request created by the new resource is appended to element’s associated background image requests.

NOTE: An Element can have several image requests, e.g. if its background-image property has multiple values. For instance, in the following example, a single background-image property produces four image requests, each of which will be recorded and reported by the algorithms below.

<!DOCTYPE html>
<style>
div {
  background-image: url(https://images.example/background1.png),
                    url(https://images.example/background2.png);
}
</style>
<div></div>
<div></div>

4.2. Recording paint timing

A pending image record is a struct with the following items:

Each Element has a set of owned text nodes, which is an ordered set of Text nodes, initially empty.

Each Document has a set of previously reported paints, which is an ordered set of strings, initially empty.

Each Document has an images pending rendering, which is a list of pending image records, initally empty.

Each Document has a set of elements with rendered text, which is an ordered set of Elements, initially empty.

4.2.1. Modifications to the CSS specification

Whenever an image request in an Element element’s associated background image requests becomes completely available, run the algorithm to process an image that finished loading with element and image request as inputs.

4.2.2. Modifications to the HTML specification

When an Element element’s associated image request has become completely available, run the algorithm to process an image that finished loading passing in element and its associated image request as inputs.

When the user agent paints a Text node text for the first time, it should execute the following steps:

4.2.3. Process image that finished loading

To process an image that finished loading given an Element element and an image request imageRequest:
  1. Let root be element’s root.

  2. If root is not a Document, return.

  3. Let now be the current high resolution time given element’s relevant global object.

  4. Let record be a pending image record with element element, request imageRequest and loadTime now.

  5. Add record to root’s images pending rendering.

4.3. Reporting paint timing

4.3.1. First Contentful Paint

To know whether Document document should report first contentful paint, perform the following steps:
  1. If document’s set of previously reported paints contains "first-contentful-paint", then return false.

  2. If document contains at least one element that is both paintable and contentful, then return true.

  3. Otherwise, return false.

4.3.2. Mark paint timing

When asked to mark paint timing given a Document document as input, perform the following steps:
  1. If the document's browsing context is not paint-timing eligible, return.

  2. Let paintTimingInfo be a new paint timing info, whose rendering update end time is the current high resolution time given document’s relevant global object.

  3. Let paintedImages be a new ordered set

  4. Let paintedTextNodes be a new ordered set

  5. For each record in doc’s images pending rendering list:

    1. If record’s request is available and ready to be painted, then run the following steps:

      1. Append record to paintedImages.

      2. Remove record from doc’s images pending rendering list.

  6. For each Element element in doc’s descendants:

    1. If element is contained in doc’s set of elements with rendered text, continue.

    2. If element’s set of owned text nodes is empty, continue.

    3. Append element to doc’s set of elements with rendered text.

    4. Append element to paintedTextNodes.

  7. Let reportedPaints be the document’s set of previously reported paints.

  8. Let flushPaintTimings be the following steps:

    1. If reportedPaints does not contain "first-paint", and the user agent is configured to mark first paint, then report paint timing given document, "first-paint", and paintTimingInfo.

      NOTE: First paint excludes the default background paint, but includes non-default background paint.

      This should be turned into a normative note.

    2. If document should report first contentful paint, then:

      1. Report paint timing given document, "first-contentful-paint", and paintTimingInfo.

      NOTE: A parent frame should not be aware of the paint events from its child iframes, and vice versa. This means that a frame that contains just iframes will have first paint (due to the enclosing boxes of the iframes) but no first contentful paint.

      NOTE: A document is not guaranteed to mark "first-paint" or "first-contentful-paint". A completely blank document may never mark first paint, and a document containing only elements that are not contentful may never mark first contentful paint.

      NOTE: The marking of first paint is optional. User-agents implementing paint timing should at the very least mark first contentful paint.

    3. Report largest contentful paint given document, paintTimingInfo, paintedImages and paintedTextNodes.

    4. Report element timing given document, paintTimingInfo, paintedImages and paintedTextNodes.

  9. If the user-agent does not support implementation-defined presentation times, call flushPaintTimings and return.

  10. Run the following steps In parallel:

    1. Wait until an implementation-defined time when the current frame has been presented to the user.

    2. Set paintTimingInfo’s implementation-defined presentation time to the current high resolution time given document’s relevant global object.

    3. If document’s cross-origin isolated capability is false, then:

      1. Coarsen paintTimingInfo’s implementation-defined presentation time to the next multiple of 4 milliseconds, or coarser.

      2. Wait until the current high resolution time is paintTimingInfo’s implementation-defined presentation time.

    4. Queue a global task on the performance timeline task source given document’s relevant global object to run flushPaintTimings.

4.3.3. Report paint timing

To report paint timing given document, paintType, and a paint timing info paintTimingInfo as arguments, perform the following steps:
  1. Create a new PerformancePaintTiming object newEntry with document’s relevant realm and set its attributes as follows:

    1. Set newEntry’s name attribute to paintType.

    2. Set newEntry’s entryType attribute to "paint".

    3. Set newEntry’s startTime attribute to the default paint timestamp given paintTimingInfo.

    4. Set newEntry’s duration attribute to 0.

  2. Set newEntry’s paint timing info to paintTimingInfo.

  3. Queue newEntry in document’s relevant realm.

  4. Append paintType to document’s set of previously reported paints.

4.4. Common algorithms

4.4.1. Exposed for paint timing

To determine whether an Element element is exposed for paint timing, given a Document or null document, perform the following steps:

  1. If element is not connected, return false.

  2. If document is null, let document be element’s relevant settings object's relevant global object's associated document.

  3. If document is not fully active, return false.

  4. If element’s root is not equal to document, return false.

  5. Return true.

5. Acknowledgements

Special thanks to all the contributors for their technical input and suggestions that led to improvements to this specification.

Conformance

Document conventions

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Conformant Algorithms

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-BACKGROUNDS-3]
Elika Etemad; Brad Kemper. CSS Backgrounds and Borders Module Level 3. 11 March 2024. CR. URL: https://www.w3.org/TR/css-backgrounds-3/
[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS Cascading and Inheritance Level 5. 13 January 2022. CR. URL: https://www.w3.org/TR/css-cascade-5/
[CSS-COLOR-3]
Tantek Çelik; Chris Lilley; David Baron. CSS Color Module Level 3. 18 January 2022. REC. URL: https://www.w3.org/TR/css-color-3/
[CSS-DISPLAY-3]
Elika Etemad; Tab Atkins Jr.. CSS Display Module Level 3. 30 March 2023. CR. URL: https://www.w3.org/TR/css-display-3/
[CSS-FONTS-4]
Chris Lilley. CSS Fonts Module Level 4. 1 February 2024. WD. URL: https://www.w3.org/TR/css-fonts-4/
[CSS-TEXT-4]
Elika Etemad; et al. CSS Text Module Level 4. 29 May 2024. WD. URL: https://www.w3.org/TR/css-text-4/
[CSS22]
Bert Bos. Cascading Style Sheets Level 2 Revision 2 (CSS 2.2) Specification. 12 April 2016. WD. URL: https://www.w3.org/TR/CSS22/
[CSSOM-VIEW-1]
Simon Pieters. CSSOM View Module. 17 March 2016. WD. URL: https://www.w3.org/TR/cssom-view-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[ELEMENT-TIMING]
Element Timing API. cg-draft. URL: https://wicg.github.io/element-timing/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. 19 July 2023. WD. URL: https://www.w3.org/TR/hr-time-3/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PERFORMANCE-TIMELINE]
Nicolas Pena Moreno. Performance Timeline. 16 February 2024. CR. URL: https://www.w3.org/TR/performance-timeline/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.. Selectors Level 4. 11 November 2022. WD. URL: https://www.w3.org/TR/selectors-4/
[SVG2]
Amelia Bellamy-Royds; et al. Scalable Vector Graphics (SVG) 2. 4 October 2018. CR. URL: https://www.w3.org/TR/SVG2/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

Informative References

[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/

IDL Index

[Exposed=Window]
interface mixin PaintTimingMixin {
    readonly attribute DOMHighResTimeStamp paintTime;
    readonly attribute DOMHighResTimeStamp? presentationTime;
};

[Exposed=Window]
interface PerformancePaintTiming : PerformanceEntry {};
PerformancePaintTiming includes PaintTimingMixin;

Issues Index

This should be turned into a normative note.
MDN

PerformancePaintTiming

In all current engines.

Firefox84+Safari14.1+Chrome60+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?