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:
-
Measuring the time when images are decoded and ready for painting
-
Measuring the time when elements are painted
-
Measuring the size of the painted elements
-
Determining whether a painted element contains any visible content.
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 perfEntryof 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:
-
The pseudo-element’s used visibility is
visible. -
The pseudo-element generates a non-empty box .
A CSS image img is a contentful image when all of the following apply:
-
img is url valued .
-
img is available .
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:
-
target has a text node child, representing non-empty text, and the node’s used opacity is greater than zero.
NOTE: this covers the case where a typographical pseudo-element would override the opacity of the text node.
-
target is a replaced element representing an available image .
-
target has a background-image which is a contentful image , and its used background-size has non-zero width and height values.
-
target is a
canvaswith its context mode set to any value other thannone. -
target is a
videoelement that represents its poster frame or the first video frame and the frame is available. -
target is an svg element with rendered descendants .
-
target is an
inputelement with a non-emptyvalueattribute. -
target is an originating element for a paintable pseudo-element that represents a contentful image or non-empty text.
An element is timing-eligible if it is one of the following:
-
an
imgelement. -
a
videoelement with a poster frame . -
an element with a contentful background-image .
-
a text node.
To compute the paintable bounding rect of element target , run the following steps:
-
Let boundingRect be the result of running the
getBoundingClientRect()on target . -
Clip boundingRect with the document ’s scrolling area .
-
Return boundingRect .
NOTE:
elements
contained
by
boxes
with
overflow
or
overflow
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:
-
el is being rendered .
-
el ’s used visibility is
visible. -
el and all of its ancestors' used opacity is greater than zero.
NOTE: there could be cases where a
paintableelement would not be visible to the user, for example in the case of text that has the same color as its background. Those elements would still considered as paintable for the purpose of computing first contentful paint . -
el ’s paintable bounding rect intersects with the scrolling area of the document .
NOTE: This covers the cases where the element is scaled to zero size, has
display, or: nonedisplaywhere the contents resolve to an empty rect.: contentsNOTE: As a general rule, an element is paintable if it is within the viewport, or can potentially be in the viewport as a result of scrolling or zooming.
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:
-
ctx is a top-level browsing context .
-
ctx is a nested browsing context , and the user agent has configured ctx to report paint timing.
NOTE: this allows user agents to enable paint-timing only for some of the frames, in addition to the main frame, if they so choose. For example, a user agent may decide to disable paint-timing for cross-origin iframes, as in some scenarios their paint-timing might reveal information about the main frame.
3.
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
- 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.
4.
The
PerformancePaintTiming
interface
[Exposed =Window ]interface :PerformancePaintTiming PerformanceEntry {};PerformancePaintTiming includes PaintTimingMixin ;
PerformancePaintTiming
extends
the
following
attributes
of
PerformanceEntry
interface:
-
The
nameattribute’s getter must return aDOMStringfor minimal frame attribution. Possible values of name are:-
: for first paint"first-paint" -
: for first contentful paint"first-contentful-paint"
-
-
The
entryTypeattribute’s getter must return."paint" -
The
startTimeattribute’s getter must return aDOMHighResTimeStampof when the paint occured. -
The
durationattribute’s getter must return 0.
NOTE:
A
user
agent
implementing
PerformancePaintTiming
would
need
to
include
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.
5.
Processing
model
4.1.
5.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.
5.2.
Recording
paint
timing
A pending image record is a struct with the following items :
-
element , an
Element -
request , an image request
-
loadTime , a
DOMHighResTimeStamp
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
Element
s,
initially
empty.
4.2.1.
5.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.
5.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.
Text
node
text
for
the
first
time,
it
should
execute
the
following
steps:
-
If text will not be painted due to the font face being in its font block period , then return.
-
Let element be the
Elementwhich determines the containing block of text . -
Append text to element ’s set of owned text nodes .
4.2.3.
5.2.3.
Process
image
that
finished
loading
Element
element
and
an
image
request
imageRequest
:
-
Let root be element ’s root .
-
If root is not a
Document, return. -
Let now be the current high resolution time given element ’s relevant global object .
-
Let record be a pending image record with element element , request imageRequest and loadTime now .
-
Add record to root ’s images pending rendering .
4.3.
5.3.
Reporting
paint
timing
4.3.1.
5.3.1.
First
Contentful
Paint
-
If document ’s set of previously reported paints contains
, then return false."first-contentful-paint" -
If document contains at least one element that is both paintable and contentful , then return true.
-
Otherwise, return false.
4.3.2.
5.3.2.
Mark
paint
timing
-
If the document ’s browsing context is not paint-timing eligible , return.
-
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 .
-
Let paintedImages be a new ordered set
-
Let paintedTextNodes be a new ordered set
-
For each record in doc ’s images pending rendering list:
-
If record ’s request is available and ready to be painted, then run the following steps:
-
Append record to paintedImages .
-
Remove record from doc ’s images pending rendering list.
-
-
-
For each
Elementelement in doc ’s descendants :-
If element is contained in doc ’s set of elements with rendered text , continue.
-
If element ’s set of owned text nodes is empty, continue.
-
Append element to doc ’s set of elements with rendered text .
-
Append element to paintedTextNodes .
-
-
Let reportedPaints be the document ’s set of previously reported paints .
-
Let frameTimingInfo be document ’s current frame timing info .
-
Set document ’s current frame timing info to null.
-
Let flushPaintTimings be the following steps:
-
If reportedPaints does not contain
, and the user agent is configured to mark first paint , then report paint timing given document ,"first-paint" , and paintTimingInfo ."first-paint" NOTE: First paint excludes the default background paint, but includes non-default background paint.
-
If document should report first contentful paint , then:
-
Report paint timing given document ,
, and paintTimingInfo ."first-contentful-paint"
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
or"first-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 ."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 .
-
-
Report largest contentful paint given document , paintTimingInfo , paintedImages and paintedTextNodes .
-
Report element timing given document , paintTimingInfo , paintedImages and paintedTextNodes .
-
If frameTimingInfo is not null, then queue a long animation frame entry given document , frameTimingInfo , and paintTimingInfo .
-
-
If the user-agent does not support implementation-defined presentation times, call flushPaintTimings and return.
-
Run the following steps In parallel :
-
Wait until an implementation-defined time when the current frame has been presented to the user.
-
Set paintTimingInfo ’s implementation-defined presentation time to the current high resolution time given document ’s relevant global object .
-
If document ’s cross-origin isolated capability is false, then:
-
Coarsen paintTimingInfo ’s implementation-defined presentation time to the next multiple of 4 milliseconds, or coarser.
-
Wait until the current high resolution time is paintTimingInfo ’s implementation-defined presentation time .
-
-
Queue a global task on the performance timeline task source given document ’s relevant global object to run flushPaintTimings .
-
4.3.3.
5.3.3.
Report
paint
timing
-
Create a new
PerformancePaintTimingobject newEntry with document ’s relevant realm and set its attributes as follows:-
Set newEntry ’s
nameattribute to paintType . -
Set newEntry ’s
entryTypeattribute to."paint" -
Set newEntry ’s
startTimeattribute to the default paint timestamp given paintTimingInfo . -
Set newEntry ’s
durationattribute to 0.
-
-
Set newEntry ’s paint timing info to paintTimingInfo .
-
Queue newEntry in document ’s relevant realm .
-
Append paintType to document ’s set of previously reported paints .
4.4.
5.4.
Common
algorithms
4.4.1.
5.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:
-
If element is not connected , return false.
-
If document is null, let document be element ’s relevant settings object ’s relevant global object ’s associated document .
-
If document is not fully active , return false.
-
If element ’s root is not equal to document , return false.
-
Return true.
5.
6.
Acknowledgements
Special thanks to all the contributors for their technical input and suggestions that led to improvements to this specification.