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
Tweet

More Decks by Harry Roberts

Other Decks in Technology

Transcript

  1. performance.now() – October 2022
    Optimising

    Largest Contentful Paint
    Harry Roberts – @csswizardry

    View full-size slide

  2. What is LCP?

    View full-size slide

  3. —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.”

    View full-size slide

  4. What Is ‘Good’?

    View full-size slide

  5. — web.dev/lcp

    View full-size slide

  6. — csswz.it/3ybF0NK
    To confirm that a threshold is
    achievable, we require that at
    least 10% of origins currently
    meet the ‘good’ threshold.

    View full-size slide

  7. Site-Speed Is More Than Just SEO

    View full-size slide

  8. €11,520,126/yr
    A 500ms improvement in LCP is worth

    View full-size slide

  9. Getting to ‘Good’

    View full-size slide

  10. Solve Everything Beforehand

    View full-size slide

  11. 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.

    View full-size slide

  12. Choose the Best Element

    View full-size slide

  13. Choose the Best Element
    Not all candidates are born equal
    elements


    elements inside an element


    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

    View full-size slide

  14. We Love Text-Based LCPs

    View full-size slide

  15. @font-face {


    ...


    font-display: [ swap | optional ];


    ...


    }

    View full-size slide

  16. What About Imagery?

    View full-size slide

  17. Time (s)
    0
    1
    2
    3
    4
    5
    in poster background-image
    4.373
    3.164
    2.619
    3.144

    View full-size slide


  18. background-image
    poster
    in

    View full-size slide

  19. Time (s)
    0
    1
    2
    3
    4
    5
    in poster background-image
    4.373
    3.164
    3.901
    3.144

    View full-size slide


  20. background-image
    poster
    in

    View full-size slide

  21. The Preload Scanner

    View full-size slide

  22. 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.

    View full-size slide

  23. After: parsing and downloading are now decoupled and asynchronous.
    Before: parse, discover, download, execute, parse, discover, download, execute, parse…

    View full-size slide

  24. in Is Bad
    What’s going on here?
    Reporting is broken— element not counted.


    is hidden from the Preload Scanner—it’s inherently slow.


    Statistically unlikely to use it, but I still wouldn’t recommend it.

    View full-size slide

  25. poster Is Good

    View full-size slide

  26. poster Is Good
    A pleasant surprise
    poster behaves much like .


    poster is available to the Preload Scanner.


    If you do have a -LCP, make sure you use poster…

    View full-size slide

  27. — 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.

    View full-size slide

  28. background-image Is Bad

    View full-size slide

  29. background-image

    View full-size slide

  30. 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.

    View full-size slide

  31. CSS Doesn’t Download Images…

    View full-size slide

  32. …The Render Tree Does

    View full-size slide

  33. — 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.

    View full-size slide

  34. 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.


    in is broken—reports very fast but is actually among the slowest.


    background-image is likely very common but also inherently slow.


    is statistically most likely and is also pretty fast.


    Google may use the first frame of a video in future. That’s gonna hurt.

    View full-size slide

  35. Common Mistakes

    View full-size slide

  36. Don’t Lazy Load Your LCP

    View full-size slide



  37. loading=lazy>

    View full-size slide

  38. — Well-meaning developers
    Can’t we just add loading=lazy and
    the browser works out what to do?

    View full-size slide

  39. loading=lazy hides the
    From the Preload Scanner

    View full-size slide

  40. img[loading=lazy] {


    outline: 10px solid red;


    }

    View full-size slide

  41. Don’t Build Your LCP

    with JavaScript

    View full-size slide

  42. LCPs built with JS contain extra steps.
    Use HTML. HTML is fast.

    View full-size slide

  43. Don’t Host Off-Site

    View full-size slide

  44. Image was 1.5× smaller, but took 2.6× longer!

    View full-size slide

  45. Don’t Usurp* Your LCP
    👑

    View full-size slide

  46. 46,287px2 32,943px2
    44,485px2 44,485px2

    View full-size slide

  47. Stretch Goals

    View full-size slide

  48. Resource Hints

    View full-size slide





  49. href=lcp.jpg>



    View full-size slide

  50. 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.

    View full-size slide

  51. Discovered after CSS; fourth request; bandwidth heavily shared. LCP approx. 2s.
    Requested in parallel with CSS; exclusive use of bandwidth. LCP approx. 1.2s.

    View full-size slide

  52. !
    Beware Google Chrome
    — csswz.it/3TcnPUv

    View full-size slide

  53. Priority Hints

    View full-size slide





  54. fetchpriority=high>



    View full-size slide

  55. 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.

    View full-size slide

  56. — csswz.it/3SCCjNh

    View full-size slide

  57. 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

    View full-size slide

  58. Image Decoding

    View full-size slide

  59. — csswz.it/3RwpeUk
    Image decoding is said to be
    synchronous if it prevents presentation
    of other content until it is finished.

    View full-size slide

  60. Image Decoding
    decoding
    Tells the browser how to deal with image decode tasks.


    decoding=sync is useful for LCP candidates.


    Also decoding=[ async | auto ].


    View full-size slide


  61. decoding=async>

    View full-size slide


  62. decoding=sync>

    View full-size slide


  63. fetchpriority=high

    decoding=sync>

    View full-size slide


  64. loading=lazy

    decoding=async>

    View full-size slide

  65. Summary
    Putting it all together…
    LCP is the final metric—solve everything that happens before it.


    Choose the best candidate—text is best; 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.

    View full-size slide

  66. Slides: csswz.it/lcp
    Thank You
    harry.is/for-hire

    View full-size slide