Optimizing Web Vitals using Lighthouse
Finding opportunities to improve user-experience with Chrome's web tooling.
Today, we'll cover new tooling features in Lighthouse, PageSpeed and DevTools to help identify how your site can improve on the Web Vitals.
As a refresher on the tools, Lighthouse is an open-source, automated tool for improving the quality of web pages. You can find it in the Chrome DevTools suite of debugging tools and run it against any web page, public or requiring authentication. You can also find Lighthouse in PageSpeed Insights, CI and WebPageTest.
Lighthouse 7.x includes new features like element screenshots, for easier visual inspection of parts of your UI impacting user-experience metrics (e.g. what nodes are contributing to layout shift).
We've also shipped support for element screenshots on PageSpeed Insights, enabling a way to more easily spot issues for one-off performance runs of pages.
Measure Core Web Vitals #
Lighthouse can synthetically measure the Core Web Vitals metrics including Largest Contentful Paint, Cumulative Layout Shift and Total Blocking Time (a lab proxy for First Input Delay). These metrics reflect loading, layout stability, and interaction readiness. Other metrics such as First Contentful Paint highlighted in the future of Core Web Vitals (CWV) are there too.
The "Metrics" section of the Lighthouse report includes lab versions of these metrics. You can use this as a summary view of what aspects of user-experience require your attention.
Field metrics, such as those found in the Chrome UX Report or RUM, do not have this limitation and are a valuable complement to lab data as they reflect the experience real users have. Field data can't offer the kinds of diagnostic information you get in the lab, so the two go hand in hand.
Identify where you can improve on Web Vitals #
Identify the Largest Contentful Paint element #
LCP is a measurement of perceived loading experience. It marks the point during page load when the primary–or "largest"–content has loaded and is visible to the user.
Lighthouse has a "Largest Contentful Paint element" audit that identifies what element was the largest contentful paint. Hovering over the element will highlight it in the main browser window.
If this element is an image, this information is a useful hint that you may want to optimize the loading of this image. Lighthouse includes a number of image optimization audits for helping you understand if your images could be better compressed, resized or delivered in a more optimal modern image format.
You might also find LCP Bookmarklet by Annie Sullivan useful for quickly identifying the LCP element with a red rectangle in just one click.
Preload late-discovered images to improve LCP #
There are a few common questions we are asked about preloading LCP images that may also be worth briefly covering.
Can you preload responsive images? Yes. Let's say we have a responsive hero image as specified using
lighthouse_1600px.jpg 1600w" sizes="50vw" alt="A helpful
Thanks to the
imagesizes attributes added to the
link attribute, we can preload a responsive image using the same image selection logic used by
<link rel="preload" as="image" href="lighthouse.jpg"
Will the audit also highlight preload opportunities if the LCP image is defined via a CSS background? Yes.
Any image flagged as the LCP image whether via CSS background or
<img> is a candidate if it's discovered at a waterfall depth of three or more.
Lazy loading offscreen images and avoiding this for LCP #
Offscreen images that are not critical to the initial user experience can be lazy-loaded. This is a technique that defers downloading an image until a user scrolls near it, which can reduce network contention for critical assets and in some cases improve LCP. The "Defer offscreen images" audit can help here:
Critical above-the-fold images, such as the Largest Contentful Paint image, should not be lazy loaded. Doing so can delay the LCP image loading. Lighthouse will highlight if an LCP image is being incorrectly lazy-loaded via the "Largest Contentful Paint image was lazily loaded" audit:
Identify CLS contributions #
Cumulative Layout Shift is a measurement of visual stability. It quantifies how much a page's content visually shifts around. Lighthouse has an audit for debugging CLS called "Avoid large layout shifts".
This audit highlights DOM elements that contribute the most to shifts of the page. In the Element column to the left you will see the list of these DOM elements and to the right, their overall CLS contribution.
Thanks to the new Lighthouse Element Screenshots feature, we can both see a visual preview of the key elements noted in the audit as well as click-to-zoom for a clearer view:
For post-load CLS, there can be value in persistently visualizing with rectangles which elements contributed the most to CLS. This is a feature you'll find in third-party tools like SpeedCurve's Core Web Vitals dashboard and which I love using Defaced's Layout Shift GIF Generator for:
For a site-wide view of layout shift issues, I get a lot of mileage out of Search Console's Core Web Vitals report. This lets me see the kinds of pages on my site with a high CLS (in this case helping self-identify what template partials I need to spend my time on):
Identifying CLS from images without dimensions #
To limit Cumulative Layout Shift being caused by images without dimensions, include width and height size attributes on your images and video elements. This approach ensures that the browser can allocate the correct amount of space in the document while the image is loading.
See Setting Height And Width On Images Is Important Again for a good write-up on the importance of thinking about image dimensions and aspect ratio.
Identifying CLS from advertisements #
Publisher Ads for Lighthouse allows you to find opportunities to improve the loading experience of ads on your page, including contributions to layout shift and long tasks that may push out how soon your page is usable by users. In Lighthouse, you can enable this via Community Plugins.
Remember that ads are one of the largest contributors to layout shifts on the web. It's important to:
- Take care when placing non-sticky ads near the top of the viewport
- Eliminate shifts by reserving the largest possible size for the ad slot
Avoid non-composited animations #
If Chrome discovers an animation couldn't be composited, it reports it to a DevTools trace Lighthouse reads, allowing it to list which elements with animations weren't composited and for what reason. You can find these in the Avoid non-composited animations audit.
Debug First Input Delay / Total Blocking Time / Long Tasks #
Lighthouse includes an Avoid long main-thread tasks audit which lists the longest tasks on the main thread. This can be helpful for identifying the worst contributors to input delay. In the left column we can see the URL of scripts responsible for long main-thread tasks.
To the right we can see the duration of these tasks. As a reminder, Long Tasks are tasks which execute for longer than 50 milliseconds. This is considered to block the main thread long enough to impact frame rate or input latency.
If considering third-party services for monitoring, I also quite like the main-thread execution timeline visual Calibre has for visualizing these costs, which highlights both parent and child tasks contributing to long tasks that impact interactivity.
Block network requests to see the before/after impact in Lighthouse #
Chrome DevTools supports blocking network requests to see the impact of individual resources being removed or not being available. This can be helpful for understanding the cost individual scripts (e.g such as third-party embeds or trackers) have on metrics like Total Blocking Time (TBT) and Time to Interactive.
Network request blocking happens to also work with Lighthouse! Let's take a quick look at the Lighthouse report for a site. The Perf score is 63/100 with a TBT of 400ms. Digging into the code, we find this site loads an Intersection Observer polyfill in Chrome which isn't necessary. Let's block it!
We can right-click on a script in the DevTools Network panel and click
Block Request URL to block it. Here we'll do this for the Intersection Observer polyfill.
Next we can re-run Lighthouse. This time we can see our performance score has improved (70/100) as has Total Blocking Time (400ms => 300ms).
Replace costly third-party embeds with a facade #
It's common to use third-party resources for embedding videos, social media posts or widgets into pages. By default, most embeds eagerly load right away and can come with costly payloads that negatively impact the user-experience. This is wasteful if the third-party isn't critical (e.g. if the user needs to scroll before they see it).
One pattern to improve performance of such widgets is to lazy-load them on user interaction. This can be done by rendering a lightweight preview of the widget (a facade) and only load the full version if a user interacts with it. Lighthouse has an audit that will recommend third-party resources which can be lazy-loaded with a facade, such as YouTube video embeds.
As a reminder, Lighthouse will highlight third-party code that blocks the main thread for over 250ms. This can expose all kinds of third-party scripts (including ones authored by Google) that may be worth better deferring or lazy loading if what they render requires scrolling to view it.
Beyond Core Web Vitals #
For more information on Core Web Vitals tooling, keep an eye on the Lighthouse team Twitter account and What's new in DevTools.
Hero image by Mercedes Mehling on Unsplash.