DEV Community

topeogunleye
topeogunleye

Posted on • Edited on

Mastering LCP: A Step-by-Step Guide to Optimizing Largest Contentful Paint for Better Web Performance

Largest Contentful Paint (LCP) is one of the three Core Web Vitals metrics. Core Web Vitals are essential performance indicators that every website owner should monitor, as they significantly impact the user experience and overall performance of web pages.
Optimizing for these metrics is crucial for the long-term success of any website. Core Web Vitals are integrated across all Google tools, making them indispensable for enhancing web performance. By focusing on these metrics, you ensure a smoother, faster, and more enjoyable experience for your users, which can lead to better engagement and higher search rankings.
Do you want to know more about Core Web Vitals metrics and tips on how to optimize for them? let’s learn

Interaction to Next Paint

Largest Contentful Shift

Largest Contentful Paint

Largest Contentful Paint (LCP): This metric gauges loading performance. To ensure a positive user experience, the LCP should occur within 2.5 seconds from when the page begins to load.
Interaction to Next Paint (INP): INP evaluates the responsiveness of a page to user interactions. For a seamless experience, the INP should be 200 milliseconds or less.
Cumulative Layout Shift (CLS): CLS measures the visual stability of a page by tracking unexpected layout shifts. To maintain a stable visual experience, pages should aim for a CLS score of 0.1 or lower.

First, let’s break down what LCP, or Largest Contentful Paint, is and why developers must understand its metrics and improve their scores. LCP measures the time it takes from when a user starts loading a web page until the largest image or text block within the viewport finishes rendering.

Google sets a benchmark for a good user experience by recommending an LCP score of 2.5 seconds or less for at least 75% of page visits. This means that if your page can render the largest image or text block within 2.5 seconds in 75% of user interactions, Google considers it to offer a fast and smooth loading experience. Understanding and optimizing LCP is key to enhancing performance and user satisfaction on your website.

An example of LCP optimization for slow experiences

In the chart above, each bar represents a real person’s loading experience when visiting this page. Typically, a site might have thousands or even millions of these data points, but for simplicity, we’re using an example with just 36 page visits. To find the 75th percentile from a sorted list of values like this, you simply need to identify the value that falls at 75%, or ¾, of the way through the list. In this example with 36 data points, the 75th percentile is represented by the 27th value in the list.

Example LCP distribution across all visits

As we can see, this value is just under 3 seconds, which falls into the "needs improvement" category. For an LCP score to be classified as "good," it must be 2.5 seconds or less. The reason we're focusing on this is to understand the impact of performance optimizations. Imagine we implement an optimization that makes all the already fast LCP experiences even faster. Notice that while the LCP times improved for some users, as shown below:

An example of LCP optimization for already fast experiences

The 75th percentile value remains unchanged. This highlights the importance of targeting optimizations that will benefit the users experiencing slower load times to truly improve overall performance.

If the site were to slightly improve the poor experiences, making them faster but still below optimal, the 75th percentile would remain unchanged:

An example of LCP optimization for slow experiences

To truly boost your LCP score at the 75th percentile, you need to enhance the experience for a significant portion of users so that at least 75% fall within the "good" threshold. The most effective strategy is to implement optimizations that improve the experience across the board, rather than focusing on a specific subset of users.

An example of an ideal situation for the LCP metric

Why the Focus on LCP

Now, you might wonder why I'm zeroing in on LCP today, instead of discussing the other Core Web Vitals metrics. The reason is simple: LCP is the metric that sites struggle with the most, according to data from the Chrome User Experience Report. While 52% of sites meet the good LCP threshold, the numbers are much higher for CLS and FID:

Why the Focus on LCP
Moreover, LCP is improving at a slower pace than the other metrics

LCP VS CLS
suggesting that developers are finding it more challenging to optimize

What Makes LCP So Hard to Optimize:

What Makes LCP So Hard to Optimize:

There are likely many reasons why LCP is difficult to optimize, but a major factor is the sheer complexity of load performance. Developers often put in a lot of effort to improve LCP, but their attempts don't always yield the desired results. The key challenge is figuring out what specific actions will make a meaningful difference for your site.

LCP is a complex problem, but like any big challenge, it becomes more manageable when you break it down into smaller, more focused problems. That’s exactly what I propose we do with LCP.

Breaking Down LCP

In the rest of this, I’ll outline a framework for how developers can improve LCP on their sites. Let’s start by looking at a typical waterfall chart from a page load, which includes CSS, JavaScript, and image resources. While all these network requests are important, when it comes to optimizing LCP, you really need to focus on just two: the HTML document and whatever other resource is required to render the LCP element.

An example of a page resource loading timeline up to LCP
While all network requests during a page load are important, when it comes to optimizing LCP, the focus should primarily be on two key resources: the HTML document and whatever additional resource is necessary to render the LCP element.

Highlight the HTML document and the LCP element

In this case, the LCP element is an image, but the same principle applies to a text node that requires a web font before it can render. Once we've pinpointed these two crucial resources, we can use their timing attributes to break down LCP into its most significant subparts. The first subpart is the time from when the user initiates the page load to when the browser receives the first byte of the HTML document response—this is known as the Time to First Byte (TTFB).

The 4 components of LCP
TTFB is critical because it marks the first moment the browser can start identifying additional resources needed to render the page, including those necessary for the LCP element. Understanding and optimizing TTFB is a foundational step in improving your LCP score.

The second subpart of LCP is the LCP resource load delay

LCP resource load delay
the time between TTFB and when the browser starts loading the resource needed for LCP. In some cases, like when the LCP element is a text node using a system font, no additional resources are needed, so the resource load delay is zero. Ideally, you want this delay to be as small as possible.

The third subpart is the time it takes to load the LCP resource. Again, if your LCP element doesn’t require an external resource, this time will be zero.

Lastly, the fourth subpart of LCP is the element render delay—the time from when the LCP resource finishes loading to when it’s rendered on the screen.

LCP element render delay
Each page’s LCP can be broken down into these four subparts, with no overlap or gaps between them. Together, they add up to the total LCP time. For example, if we reduce the resource load time, the element render delay might extend by the same amount, meaning the overall LCP doesn’t change.

If we compress the image, in this timeline, LCP does not change

This happens because the page might be waiting for JavaScript (those yellow bars at the bottom) to load before adding the LCP element.

This point is crucial and often a source of frustration for developers. When seeking advice on improving LCP, one of the most common suggestions is to optimize images. However, optimizing images only affects one part of LCP. If this part isn’t your bottleneck, then reducing it won’t improve your score, as seen in this example.

Best Practices Within Each Subpart of LCP

The key to improving LCP is identifying where your bottlenecks are. To do this, it’s helpful to know the ideal or recommended values for each LCP subpart. At a high level, the advice is straightforward.

High-Level Goals: Optimizing LCP Timing

When optimizing for LCP, your main objective is clear: spend most of your time on the network requests necessary to render the LCP element. Anything that delays the start of loading the LCP resource or slows down rendering after the resource is loaded is essentially wasted time.

In an ideal scenario, here’s how these LCP subparts should break down on a well-optimized page:

Reference values ​​for LCP components

The total time on the right is based on the goal of a 2.5-second LCP, with other times proportionally distributed. Notice that around 80% of the time is dedicated to network requests, while only 20% is allocated to everything else. Later, I’ll walk you through a real-world example of a performance optimization, using this 80-20 principle to pinpoint improvement opportunities.

LCP Broken Down

Real-World Data Insights

Curious about how time is spent across LCP subparts in real-world sites? While we don’t have real user data for these specific metrics, we do have lab data from the HTTP Archive. This data comes from 5.3 million web page test runs, focusing on pages where the LCP element was an image with a URL source.

LCP Broken Down Analysis

Here’s how the data breaks down:

I sorted all runs by LCP value, from fastest to slowest, and divided them into five buckets. The top bucket represents the fastest 20% of pages, while the bottom represents the slowest 20%. For each bucket, I averaged the LCP subpart times to create stacked bars, where the total length represents the average LCP value in that bucket.

LCP components in online web pages, in order of LCP

A Surprising Discovery

When I first saw this data, I was surprised. I expected the majority of LCP time would be spent loading large, unoptimized images—anticipating those green bars to dominate, especially in the slowest bucket. However, the data suggests that image load times might not be the main bottleneck. Instead, the purple segments, representing resource load delay, appear to be the biggest issue.

Now, keep in mind that this is lab data, not real-world data. The tests use a single network and device configuration for each run, so it’s not fully representative of the diverse devices and networks used in real life. Additionally, HTTP Archive tests don’t account for repeat visits, meaning the user’s cache state isn’t factored in. While we can’t definitively say this is how LCP breakdowns look in the wild, it’s clear that sites could be doing a better job optimizing LCP resource loads.

Optimism Amid Challenges

Despite these challenges, there’s reason for optimism. The subparts of LCP that are hardest to improve—represented by the blue and green segments—are fewer in number. The purple and yellow segments, representing the parts of LCP that are easiest to improve, show ample opportunity for enhancement. By helping developers identify their bottlenecks, we could see significant improvements in LCP across the board.

Recipe for LCP Optimization: A Step-by-Step Approach

There are only four steps to optimize LCP, ordered by ease and impact:

Step 1: Eliminate Unnecessary Resource Load Delay

The key here is to prioritize the LCP resource so it starts loading immediately after the HTML document is received. To check if your page’s LCP resource is loading early enough, compare its request start time with the start time of the first sub-resource.

An example of project time

If the LCP image starts loading later than, say, a stylesheet starts loading before it, that’s a sign there’s room for improvement. You can fix this by using preload or adding priority hints to the image tag, prompting the browser to start loading it sooner. Also, ensure the LCP image isn’t lazy-loaded, as that could introduce unwanted delays. Preloading the image should solve this issue.

Here’s what happens after implementing these changes:

An example of project time reduction

Now, the image resource starts loading simultaneously with the first stylesheet, exactly as intended. Step one is done. But remember, reducing resource load delay won’t necessarily improve LCP if it’s still blocked by JavaScript, as mentioned earlier.

Tips:

  • Add priority hints or preload
  • Minimize network connections
  • Use same-origin resources (if possible)

Step 2: Eliminate Unnecessary Element Render Delay

To optimize LCP, it's crucial to ensure that once the LCP resource finishes loading, nothing else on the page delays its rendering. Any delay here can prevent the LCP element from appearing as quickly as possible.

Tips:

  • Remove or minimize render-blocking stylesheets.
  • Defer render-blocking JavaScript.
  • Use font-display: optional for web fonts.

Example:
One way to reduce render times is by optimizing the size of the JavaScript files being loaded. Techniques like minification and tree shaking can reduce script download times, improving overall performance.

An example of optimizing resource rendering delay<br>

While this is an improvement, it’s still not ideal. The goal is to eliminate anything that blocks rendering after the LCP resource finishes loading, not just reduce blocking time. For instance, if the JavaScript code is client-side rendering the application, updating the framework to use server-side rendering or pre-rendering pages as static files can prevent JavaScript from blocking the LCP image render.

An example of optimizing the LCP metric by changing the rendering of the resource

With this update, the JavaScript code no longer blocks rendering, allowing the LCP image to appear immediately after it’s downloaded.

Step 3: Reduce Resource Loading Time

The third step is to minimize the resource load time as much as possible by following best practices for optimizing images and web fonts. Anything that reduces the file size of the resource will help reduce load times.

Tips:

  • Compress images.
  • Use modern image formats like AVIF or WebP.
  • Properly sized images.
  • Set far-future cache expiry headers.
  • Use a CDN to reduce network distance.

An example of reducing LCP resource loading time<br>

Example:
In the example above, optimizing the LCP resource so much that it becomes smaller than the stylesheet can lead to the stylesheet blocking rendering. To prevent this, consider techniques like critical CSS or removing unused styles where possible. Alternatively, you can inline CSS into the document, though this might have negative effects on performance for repeat visitors.

The best approach is to reduce the size of the stylesheet so it’s smaller than the LCP resource, ensuring it’s not blocking or rarely blocking, which is a good compromise.

An example of reducing LCP resource loading time

In this case, slightly reducing the stylesheet’s size is enough to prevent it from blocking the LCP image’s rendering.

Step 4: Reduce Time to First Byte (TTFB)

The final step, reducing TTFB, is often the hardest for developers to optimize and typically the one with the least control. However, having a good TTFB is critical because it impacts everything that follows.
Here is a Visual Illustration of improving TTFP:
An example of TTFB (Time To First Byte) optimization<br>

Tips:

Use a CDN to reduce network distance, getting servers closer to users.
Upgrade server hardware for faster processing.
Ensure the response body can be streamed.

Improving TTFB will directly enhance every subsequent step, as nothing can happen on the front end until the back end delivers the first byte of the response.


Recap:

  1. Start Early: Ensure the LCP resource starts loading as soon as possible.
  2. Render Immediately: Ensure the LCP element can render immediately after its resource finishes loading.
  3. Reduce Load Times: Minimize the load time of the LCP resource without compromising quality.
  4. Deliver Fast: Deliver the initial HTML document as quickly as possible.

By following these four steps, you can ensure an optimal loading experience for your users, which should be reflected in improved real-world LCP scores.

Conclusion

Optimizing the Largest Contentful Paint (LCP) is like setting the stage for a great first impression on your website. Imagine your visitors arriving at your site, eager to see what you have to offer. The speed at which the main content loads plays a huge role in whether they stick around or leave. By honing in on four key areas—getting the most important content to load early, avoiding any delays in rendering, speeding up resource load times, and cutting down the time it takes to get the first bit of data to the browser—you can make sure your site performs at its best.

These steps aren’t just about making small tweaks here and there. It’s about creating a smoother, faster experience that all your users will appreciate. When you get these optimizations right, you’re not just improving a single metric; you’re boosting the overall experience, making your site feel faster and more responsive. In the long run, this means happier users, better satisfaction, and stronger LCP scores. By carefully identifying and tackling performance bottlenecks, you can ensure your site remains speedy and robust, even as new challenges arise.

Top comments (0)