Codementor Events

Measuring Largest Contentful Paint

Published Oct 13, 2020
Measuring Largest Contentful Paint

Largest Contentful Paint (LCP) is a measurement of how long the largest element on the page takes to render. It’s one of several Web Vital metrics that measure how real users perceive the performance of modern web applications. New measurements like Largest Contentful Paint are increasingly important as JavaScript and SPA’s render more content after page load is completed.

Largest Contentful Paint

The Largest Contentful Paint metric works under the assumption that the page is useful to the user once they can see the largest piece of content. It’s an important “core web vital” metric that Google will soon be considering when ranking search results.

LCP is not a single measurement, but a series of measurements. An additional LargestContentfulPaint entry is created every time a new largest element is rendered. The LCP metric can be boiled down to a single value by using the last LargestContentfulPaint entry in a page load. Only image, video and text-containing block level elements can trigger LCP entries.

What constitutes “largest” varies by element type. Image element size is determined by the size of the image as shown on the page. Text-containing element size is the smallest box than encompasses the text itself.

In this contrived example, the largest rendered element is highlighted. Some elements are in the base HTML and rendered right away. Later, JavaScript inserts additional elements:

largest-contentful-paint-example.gif

But what is a good value for Largest Contentful Paint? Helpfully, Google has determined some recommended times using data gathered from the Chrome browser:

LCP Scores

Largest Contentful Paint API

The Largest Contentful Paint API is a proposed standard to expose largest paint measurements through JavaScript. It is currently supported in Blink-based browsers, such as Chrome, Edge, and Opera. NOTE: As a draft standard, there are occasionally changes to how LCP is determined.

We can test the API’s behavior with a little code:

new PerformanceObserver(entryList => {
    console.log(entryList.getEntries());
}).observe({ type: "largest-contentful-paint", buffered: true });

Note that the buffered: true option returns all entries that occurred before the PerformanceObserver was configured. The sloth example page returns entries like this:

LargestContentfulPaint performance entries LargestContentfulPaint performance entries

LCP Production API Quirks and Gotchas

The API example above glossed over a few issues and surprising behavior that need to be considered before being used in a production setting.

1. Don’t Measure Pages Loaded In The Background!

Last Contentful Paint should not be measured when the page is loaded in a background tab. The measurement only indicates when the user first brought the tab to the foreground in that case. An additional check prevents measurement of background tabs:

var hiddenTime = document.visibilityState === 'hidden' ? 0 : Infinity;

document.addEventListener('visibilitychange', (event) => {
    hiddenTime = Math.min(hiddenTime, event.timeStamp);
}, { once: true });

new PerformanceObserver(entryList => {
    entryList.getEntries().forEach((entry) => {
        if (entry.startTime < hiddenTime) {
            // This entry occurred before the page was hidden
            console.log(entry);
        }
    };
}).observe({ type: "largest-contentful-paint", buffered: true });

2. Largest Contentful Paint API Feature Detection

Not all browsers support the Largest Contentful Paint API. Try/catch is the only reliable way to detect the feature because some browsers throw an exception when the API is used:

try {
    new PerformanceObserver(entryList => {
        console.log(entryList.getEntries());
    })
    // Some browsers throw when 'type' is passed:
    .observe({ type: "largest-contentful-paint", buffered: true });
}
catch (e) {
    // The Largest Contentful Paint API is not supported by this browser
}

3. LargestContentfulPaint Entries Can “Revert” To Previous Values

Previous LargestContentfulPaint entries can be re-issued if the current “largest element” is removed from the DOM. The last entry returned from entryList.getEntries() has a shorter startTime than the previous entry when this happens:

Largest Contentful Paint reverts on element removal.

4. A Block Element’s Border and Background Do Not Contribute To Its Size

The “largest” element in LargestContentfulPaint entries can be rather un-expected. Often, the visually largest element is not largest according to the LCP size rules. This happens because borders and colored backgrounds are not included in an element’s size calculation. Only the text’s bounding box is used:

Largest Contentful Paint: Unexpected largest element

5. User Interaction Stops Further LCP Entries

New LargestContentfulPaint entries are created while content continues to render and the user has not interacted with the page. As soon as the page is clicked or scrolled, LCP measurements are halted. Ironically, users who interact with a slow page out of frustration can hide the actual largest paint:

User Interactions Stop LargestContentfulPaint measurements

Conclusion

As the above quirks show, Largest Contentful Paint doesn’t always tell the whole story. It is just another tool in the web performance toolbox. When paired with traditional performance measurements and other new ones like Cumulative Layout Shift, a better understanding of your users’ experience can be seen.


LCP Performance Monitoring

Let us handle the hard stuff. Monitor your real-user web vitals like Largest Contentful Paint with Request Metrics.

Web Vital Performance Metrics

Discover and read more posts from Todd Gardner
get started
post commentsBe the first to share your opinion
Show more replies