The experience of navigating and using a web page is defined by four key moments:
- it is happening;
- it is useful;
- it is usable;
- it is delightful.
First Paint (FP) and First Contentful Paint (FCP) are the first key progress metrics focused on giving the perception that the page is happening. They mark the point immediately after navigation when the browser renders pixels to the screen.
The main difference between the two metrics is the following:
- FP is the exact time the browser renders anything as visually different from what was on the screen before navigation, e.g. a background change after a long blank white screen time.
- FCP is the exact time the browser renders the first bit of content from the DOM, which can be anything from an important image, text, or even the small SVG at the bottom of the page.
Together they refer to the precise time at which navigation started successfully, with elements rendered to the page and showing that it is happening.
Web performance APIs, available in multiple browsers, are the solution to these real world measurements.
We use the PerformanceObserver interface to observe and receive notifications about new performance metrics as they are recorded in the Performance Timeline. Those accurate measurements result in High Resolution Time (DOMHighResTimeStamp) values present inside the Performance Entry object.
We create a performance observer, instructed to observe specific entry types, including; “measure”, “resource”, “longtask” and most importantly, “paint”. The callback is invoked asynchronously as soon as the entries of that types become available.
All entries are surfaced by the PerformanceEntryList object, which by the method getEntries() come easy iterate through all the sequence of PerformanceEntry.
To report the time of FP and FCP, the PerformanceEntry has been extended to the new interface PerformancePaintTiming (under development as W3C draft), which will differ by the name values: “first-paint”, “first-contentful-paint”.
API’s in practice
Let’s play with a live demo. We have an empty page where there are two DOM changes, the first is the background color, and the last is an H1 attached to the BODY with a simple text. With PerformanceObeserver we observe the entry type “paint” which asynchronously will return two measurements:
- “first-paint” when the yellow background is visible after navigation, in the scenario around 400ms;
- “first-contentful-paint” when the H1 is rendered to the DOM, for the purpose of this demo we waited 600 ms before executing and ending with a final measurement of 1 second.
This demo works well in Chrome where from v60 the FP and FCP APIs are supported. But for other browsers, we still have to wait for the full support of these new APIs. You can follow this bug to keep track of when the support will land on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1403027 .
A touch of Perfume.js
The results are the same as in the previous demo, with two extra important advantages:
- cross-browser support, which will use the modern native APIs when available and some emulated methods for other scenarios;
- reporting the metrics results to Google Analytics User timing which supports the custom user timing variable timingVar:”name”.
In a large web project with multiple engineers contributing to the same initial JS bundle size, monitoring FP is a significant way to catch regressions and indicates to the user the browser has started rendering.
Usually, FCP is a less reliable metric, because it will catch meaningless things such as a copyright image but at the same time for a single page app where most of the content is rendered at the same time, the first contentful paint metric plays a major role.
Now, take a few extra minutes and start measuring the metrics for your app! Have fun 🔥 🚀 🌕
For extra questions, send me a tweet or a private message at Twitter @zizzamia.