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

Optimising Largest Contentful Paint

Harry Roberts
October 06, 2022

Optimising Largest Contentful Paint

Since Google announced their Core Web Vitals (CWV) initiative, being fast is more important than ever. However, despite being by far the easiest CWV to monitor, debug, and optimise—in both the lab and field—Largest Contentful Paint (LCP) is still the one that most websites struggle with.

In this very practical talk, we’ll look at what exactly comprises LCP, how we might be working against ourselves, and how to make opportunistic optimisations to get ourselves back in the green (and beyond).

And even if none of those terms meant anything to you, don’t worry! You’ll leave this talk fully equipped to go back to your own projects and clients and make all the improvements they’ll need. Get ready to ask for a pay rise.

Harry Roberts

October 06, 2022

More Decks by Harry Roberts

Other Decks in Technology


  1. —web.dev/lcp “Largest Contentful Paint (LCP) is an important, user-centric metric

    for measuring perceived load speed because it marks the point in the page load timeline when the page’s main content has likely loaded—a fast LCP helps reassure the user that the page is useful.”
  2. — csswz.it/3ybF0NK To confirm that a threshold is achievable, we

    require that at least 10% of origins currently meet the ‘good’ threshold.
  3. Solve Everything Beforehand LCP is a milestone timing DNS, TCP,

    TLS Redirects TTFB* First Paint First Contentful Paint* If any of these are slow, you’re already on the back foot.
  4. Choose the Best Element Not all candidates are born equal

    <img> elements <image> elements inside an <svg> element <video> elements (the poster image is used) An element with a background image loaded via the url() function (as opposed to a CSS gradient) Block-level elements containing text nodes or other inline-level text element children. web.dev/lcp
  5. <head> <script src=script.js></script> </head> <body> <!-- - LCP Candidate -

    - <img> | <image> in <svg> | poster | background-image --> </body>
  6. Time (s) 0 1 2 3 4 5 <img> <image>

    in <svg> poster background-image 4.373 3.164 2.619 3.144
  7. Time (s) 0 1 2 3 4 5 <img> <image>

    in <svg> poster background-image 4.373 3.164 3.901 3.144
  8. The Preload Scanner Faster for free… Invented in IE8 as

    the ‘Speculative Pre-Parser’. A secondary, inert, asynchronous, download-only parser. Decouples resource discovery/download from runtime executions. Made the web a lot, lot faster. In every single modern browser. Some resources are visible to the Preload Scanner, some are not.
  9. After: parsing and downloading are now decoupled and asynchronous. Before:

    parse, discover, download, execute, parse, discover, download, execute, parse…
  10. <image> in <svg> Is Bad What’s going on here? Reporting

    is broken—<image> element not counted. <image> is hidden from the Preload Scanner—it’s inherently slow. Statistically unlikely to use it, but I still wouldn’t recommend it.
  11. poster Is Good A pleasant surprise poster behaves much like

    <img>. poster is available to the Preload Scanner. If you do have a <video>-LCP, make sure you use poster…
  12. — csswz.it/3Cp1Js5 Currently, a video element with a poster image

    will have that poster image considered for LCP, but without one, whether it is not present or the video autoplays, the video is ignored (for LCP purposes). The first frame of a video, when painted, should be considered as an LCP candidate.
  13. background-image Is Bad No surprise at all background-image is hidden

    from the Preload Scanner. Background images are late-discovered resources. Browsers only request background images (and web fonts) if it knows the page needs them… And it doesn’t know that until it encounters the DOM node that needs it. background-image is inherently slow.
  14. — csswz.it/3rvESok The reason these resources (in this specific case,

    background images) are slow is because they aren’t requested until the browser is ready to paint the DOM node that needs them.
  15. Not All Candidates Are Born Equal Takeaways… Ideally, a text-based

    candidate with appropriate font-display will be fastest. poster is nice and fast, but statistically unlikely to be used. <image> in <svg> is broken—reports very fast but is actually among the slowest. background-image is likely very common but also inherently slow. <img> is statistically most likely and is also pretty fast. Google may use the first frame of a video in future. That’s gonna hurt.
  16. Resource Hints preload rel=preload is useful for late discovered resources.

    The clue is in the name—remember the Preload Scanner? This exposes otherwise hidden resources to the Preload Scanner. Generally speaking, don’t use rel=preload for resources already available in HTML. Useful if your LCP candidate is a background-image.
  17. Discovered after CSS; fourth request; bandwidth heavily shared. LCP approx.

    2s. Requested in parallel with CSS; exclusive use of bandwidth. LCP approx. 1.2s.
  18. Priority Hints fetchpriority fetchpriority=high is useful for in-page resources. Also

    fetchpriority=[ low | auto ]. Reduces amount of time spent queueing. This is amazing. Allows us to control priorities! We need to understand what priorities are.
  19. auto high Change Discovered 794ms 771ms -23ms Queuing 2,160ms 0.85ms

    -2,159.15ms Duration 12,030ms 5,370ms -6,660ms LCP 13,795ms 4,960ms -8,835ms
  20. — csswz.it/3RwpeUk Image decoding is said to be synchronous if

    it prevents presentation of other content until it is finished.
  21. Image Decoding decoding Tells the browser how to deal with

    image decode tasks. decoding=sync is useful for LCP candidates. Also decoding=[ async | auto ].
  22. Summary Putting it all together… LCP is the final metric—solve

    everything that happens before it. Choose the best candidate—text is best; <img> is good. Expose the LCP candidate early—we love HTML! Don’t work against yourself—don’t make silly mistakes. Step in and help the browser—use new APIs to push things further. Use new features sparingly—test everything.