Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Core Web Vitals and their effect on User Experi...

Core Web Vitals and their effect on User Experience

The Core Web Vitals - Largest Contentful Paint, Interaction to Next Paint, and Cumulative Layout Shift - were chosen because they are a close proxy for how good or bad a user experience is. There are some things to be aware of... Are they available on all page types, or across browsers, when do they become available, how do we capture them, etc.

In this talk we'll understand what the Core Web Vitals are and how to make use of them.

https://confoo.ca/en/2025/session/core-web-vitals-and-their-effect-on-user-experience

Leave feedback at https://confoo.ca/en/2025/feedback/D0D5DA589D54778514141144094BA3C0

Philip Tellis

February 27, 2025
Tweet

More Decks by Philip Tellis

Other Decks in Technology

Transcript

  1. Abbé Jean-Antoine Nollet 1700 - 1770 French Clergyman & Budding

    Electrician Invented one of the first Electroscopes (we now call them beacon collectors) L'Abbé Jean Antoine Nollet — Maurice Quentin de La Tour Alte Pinakothek, Munich, Germany Public Domain
  2. Philip Tellis Principal RUM Distiller @ Akamai • Creator of

    mPulse and tinkerer of the data • Author of the OpenSource boomerang RUM library social:@bluesmoon ⦿ github:@bluesmoon speakerdeck:@bluesmoon
  3. LCP reports the render time of the largest image, text

    block, or video visible in the viewport. https://web.dev/articles/lcp
  4. ★ Render time ★ Foreground or background Images including inline

    ★ “Largest” is related to rendered screen size ★ Text nodes ★ Only rendered portions after clipping ★ Not related to download time ★ No CSS gradient backgrounds ★ No placeholders or low entropy images ★ Nothing invisible ★ Text nodes using Web Fonts during the Font block period What does this include / exclude?
  5. new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) {

    // element, id, url, // renderTime, loadTime, size } }).observe({ type: "largest-contentful-paint", buffered: true }); performance.getEntriesByType("largest-contentful-paint") is deprecated!
  6. Object Structure • element: A reference to the DOM element

    that was painted • id: The id attribute of the element • url: The Url for images. This might also be a data uri. • renderTime: The relative timestamp when the object was rendered, 0 for cross-origin objects without T-A-O. • loadTime: The relative timestamp when the object was loaded. • size: The number of square pixels rendered (height x width) https://developer.mozilla.org/en-US/docs/Web/API/LargestContentfulPaint
  7. < 2.5s Google suggests keeping the value under 2.5s at

    the 75th percentile (that’s about as long as a yawn)
  8. CLS is a measure of the largest burst of layout

    shift scores for every unexpected layout shift that occurs during the entire lifecycle of a page. https://web.dev/articles/cls Layout Shift is a fractional value between 0 and 1
  9. new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) {

    // sources, // value, // hadRecentInput, // lastInputTime, // startTime } }).observe({type: "layout-shift",buffered: true});
  10. Object Structure • sources: A list of Layout Shift Attributions:

    ◦ node: The node that shifted; Null if no longer in the DOM ◦ previousRect, currentRect • startTime: Relative timestamp when the layout shift started. • value: The layout shift value. • lastInputTime: Relative timestamp of the most recent excluding input. • hadRecentInput: true if the above was less than 500ms https://developer.mozilla.org/en-US/docs/Web/API/LayoutShift
  11. Interaction to Next Paint (INP) How long did the user

    have to wait after doing something on the page?
  12. INP is a measure of the page’s overall responsiveness to

    user interactions. https://web.dev/articles/inp INP is the (approx) longest observed interaction latency so far.
  13. new PerformanceObserver((entryList) => { for (const entry of entryList.getEntries()) {

    // target (null if removed), // duration, // startTime, // processingStart, // processingEnd } }).observe({ type: "event", buffered: true, durationThreshold: 16 }); https://developer.mozilla.org/en-US/docs/Web/API/PerformanceEventTiming
  14. < 200ms Google suggests keeping the value under 200ms at

    the 75th percentile (blink of an eye is 300ms)
  15. ★ Includes a start time & duration ★ Can collect

    this value incrementally to identify all INP durations on the page ★ You need to maintain your own interaction buffer. ★ Remember to reset the buffer for multiple transitions in a SPA. ★ Not all pages have an interaction. ★ Disable your listener if the page is not visible Notes…
  16. A fast LCP is a signal to the user that

    the page is ready for Interactions % of users who interact
  17. A fast LCP is a signal to the user that

    the page is ready for Interactions INP value for those interactions
  18. A fast LCP is a signal to the user that

    the page is ready for Interactions Rage clicks for users that interacted at this time
  19. A fast LCP is a signal to the user that

    the page is ready for Interactions This is when the page looks complete
  20. A fast LCP is a signal to the user that

    the page is ready for Interactions This is when the page is usable