Website speed plays an important role in engaging and retaining online users. Largest Contentful Paint (LCP), a crucial metric in web performance, directly impacts user experience and SEO rankings by measuring how quickly the main content loads on a webpage.
LCP optimization involves strategies aimed at accelerating the loading of essential page elements, thereby enhancing user satisfaction and search engine visibility. If you’re just curious or think you have performance issues (in which case, we need hard numbers first) – real user data is best here.
Google, hosting companies, and online services provide tools known as real user monitoring (RUM) that allow you to collect and view user data such as performance.
If you don’t collect it, you can use, for example, webpagetest or pagespeed).
This article explores effective techniques to improve LCP, empowering businesses to achieve both better performance metrics and higher rankings in search results.
So, let’s get right into it!
What is LCP (Breakdown)?
What is it? LCP stands for Largest Contentful Paint; it is one of the Core Web Vitals (CWV) metrics that is used to evaluate the performance of a web page.
In short, it is a measure of how quickly you can deliver and show content to users. LCP score directly affects SEO: the better the LCP, the better the SEO.
Please do not confuse it with FCP (First Contentful Paint) – the two mean different things.: FCP indicates the first appearance of content (not necessarily main content) on the screen and has only one entry, whereas LCP measures until the end of loading (more precisely, before the first user interaction) and can have multiple entries.
Since larger elements may appear in the viewport while the page is loading, only the last – the largest element – will be taken as the metric value.
But sometimes, they can point to the same element. Let’s look at some examples to better understand.
Regardless of special tools, we can extract performance metrics manually right in a browser console during a session.
new PerformanceObserver((list) => console.log(list.getEntries())).observe({
type: "paint",
buffered: true,
});
new PerformanceObserver((list) => console.log(list.getEntries())).observe({
type: "largest-contentful-paint",
buffered: true,
});
For example, the FCP and LCP of this web page have the same time. We also only have one entry for LCP. This means that FCP corresponds to LCP.
Browser console output:
But it was an ideal scenario, and we usually have a different picture. There are several LCP entries on this web page, none of which correspond to larger items appearing during loading until the largest one appears, which will be the LCP.
According to httparchive, a significant number of websites have problems with LCP, so this may be a sign that getting a good score on LCP may not be easy.
The main reason for this is the LCP complexity: we need to think about content and speed at the same time. Even the default text element isn’t necessarily fast, let alone images.
What counts as content? – Since this is a user-centric metric, we are interested in contentful blocks of information, and only visible elements can be candidates for LCP.
The contentful element is the largest and most significant piece of content within the user’s viewport.
It can be an image, a block of text, or a video. Speed corresponds to time here – the time it takes to load and display an element to the user.
Moving from the last event to the first: before rendering, we need to load a resource for the element – an image or a web font; to load the resource first we need to detect the element and its resource URL and before that we need to load the HTML document first.
Google defined these stages as follows: now from the first event to the last:
- TTFB is the time to the first byte. This is a measure of how quickly your server can send an HTML document to a user upon request.
- Load delay is a measure of the time between the TTFB and the start of loading of the LCP element.
- Load time is the time it takes to load the resource.
- The render delay time is the time between states when the browser has everything to render your LCP but has not yet rendered it.
Here are some details about which element can be an LCP candidate. LCP has its own specification, according to which it can be an image or text. No restrictions for text.
An image can be provided by the following tags: <img/>, <video/>, <image/> within a <svg/>, but <svg/> itself can’t be an LCP.
A CSS pattern will not be treated as LCP, but a background with an image provided in the url() will. For animated images (GIFs) or videos, only the first frame (thumbnail) will be considered as a candidate for LCP.
If an image fills the entire viewport, it will not be considered an LCP but rather a background.
There are some limitations in measuring LCP.
Also read: Failed Core Web Vitals Assessment? Here’s How To Fix It
Ways to Improve LCP Performance
It should be noted that to improve performance you need to prioritize the resources that are critical to rendering everything in the user’s viewport and put everything else aside. It’s useful to know the browser’s critical rendering path (CRP).
What we will improve is the timings, but we also need to consider both text and images.
We will follow Google’s timing model for LCP. The sum of all timings must be less than 2.5 seconds to be considered good.
But each part has completely different reasons. Moreover, sometimes when you reduce one part, you simply increase the adjacent part to the same amount, leaving the overall time the same. So to make real improvement you need to improve all timings – each timing should be as short as possible.
- TTFB: This performance metric refers to the point at which the user begins receiving data. Therefore, we must send data as soon as possible after user interaction. Each additional step will potentially increase this time. It can sometimes be difficult to improve and this metric deserves its own article, but we can limit ourselves to the following tips:
- Avoid redirects that can impact TTFB because they introduce additional steps in the process of fulfilling a user’s request for a web page.
- Optimize server response times by using efficient hosting, CDNs, and caching mechanisms. If you use server-side rendering (SSR), ensure it is fast, and switch to static site generation (SSG) if possible.
- Some frameworks support streaming from the server – which allows you to start sending HTML even if it is not completely ready.
What is good: 0.8 seconds or less
- Load delay: This is the time between TTFB and the start of loading. To start loading, the browser needs to scan (preload scanner) the page to understand what resources it needs to render in order to start loading it. And if you don’t give the browser any hint, it will only find those resources when it encounters an img element or text node with a required web font. Sometimes, it’s a significant portion of the time. To reduce this time, you can add <link/> tags in the <head> for the web font and images that could potentially be LCP. Let’s consider fonts first. For Google fonts, it could be something like this:
<link rel="preload" href="https://fonts.googleapis.com/css?family=Roboto&display=swap" as="style" crossorigin="anonymous"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto&display=swap" crossorigin="anonymous"/>
Since it’s a separate HTTPS connection, serving those fonts from your server may be faster.
<link rel="preload" href="/fonts/Roboto/RobotoBold.woff2" as="font" type="font/woff2">
<link rel="stylesheet" href="styles/fonts.css"/>
But I suggest testing both approaches to see which is the fastest in your case.
For images, it looks very similar.
<link rel="preload" as="image" href="https://imagecdn.com/some-image.webp">
The background image cannot be preloaded this way, but you can embed the image in CSS using the data URI and then inline styles in the <head>.
So, instead of using an image link:
.cool-background {
background: url("image.png");
}
You can insert an encoded image string into the URL:
.cool-background {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAABmCAMAAADS3TdOAAACTFBMVEX/////TkIqef8Jzmv/pABmZmZDQ0MAAAD/89z/5+X/7c7d+OvQ9uL/3dpFiP+Ktf+ewv9+5bJra2t0vD36+voMBgGsyv/d3d2kpKT39/dtbW0EAwHEfgJ5eXkjFgPcjgL....")
}
There are a few pitfalls to this approach: the base64 string will weigh more in KB than the original image, not to mention increasing the overall weight of the page, and the browser will also waste more main thread resources decoding the string into the actual image and finally, the image won’t be cached.
If you are using SVG, then instead of using <img> with a src link to the SVG file, you can include the SVG in the HTML. So instead of:
<img src="logo.svg" />
You can do something like this:
<svg xmlns=”https://www.w3.org/2000/svg” width=”400″ height=”400″ viewBox=”0 0 124 124″ fill=”none”>
<rect width="124" height="124" rx="24" fill="#F97316"/>
<path d="M19.375 36.7818V100.625C19.375 102.834 21.1659 104.625 23.375 104.625H87.2181C90.7818 104.625 92.5664 100.316 90.0466 97.7966L26.2034 33.9534C23.6836 31.4336 19.375 33.2182 19.375 36.7818Z" fill="white"/>
<circle cx="63.2109" cy="37.5391" r="18.1641" fill="black"/>
<rect opacity="0.4" x="81.1328" y="80.7198" width="17.5687" height="17.3876" rx="4" transform="rotate(-45 81.1328 80.7198)" fill="#FDBA74"/>
</svg>
The <link/> element can also include a fetchpriority attribute with values of ‘high’, ‘low’, or ‘auto’ (default). This attribute allows for more precise control over resource loading. Setting it to ‘high’ prioritizes the resource, while ‘low’ reduces its priority, though the browser can elevate it if needed.
While you can use this attribute directly in <img/> tags, it’s preferable to include it in the <head> section for earlier detection by browsers. Currently, global support stands at approximately 78%.
<img src="image.jpg" fetchpriority="high">
Note: Overusing fetchpriority=”high” can diminish its effectiveness. When everything is a ‘high’ priority, essential resources may be queued alongside others, potentially lowering performance.
You can also optimize by preconnecting to necessary hosting resources:
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>
To illustrate potential savings, consider results from webpagetest under different network conditions:
4G connection: 9000/9000 Kbps, latency 170ms, total connection time 353ms.
3G connection: 1600/768 Kbps, latency 300ms, total connection time 647ms. These metrics highlight the benefits of pre-connecting to improve Time To Interactive, as seen with
Note that: chrome.com reduces it by nearly 1 second through important origin pre-connection.
For optimal load times, focus on resource weight reduction since user connection speeds remain constant:
- Use lossless compression and resizing for images to reduce file sizes without compromising quality.
- Consider modern formats like WebP for better compression efficiency, which is widely supported across browsers.
- Utilize browser caching and CDNs for static assets to enhance delivery speed.
- Implement responsive images to display appropriately sized images based on viewport dimensions.
<img srcset="image-small.jpg 480w, image-big.jpg 800w" sizes="(max-width: 600px) 480px, 800px" src="image-big.jpg" />
Ensure correct image selection by considering device pixel ratio (DPR):
<img srcset="image-small.jpg 1.5x, image-big.jpg 2x" src="image-big.jpg" />
For further DPR-based optimization, use <picture> with multiple sources:
<picture>
<source media="(-webkit-min-device-pixel-ratio: 3) and (-webkit-max-device-pixel-ratio: 3.9)" srcset="...">
<img alt="image" sizes="100vw" srcset="...">
</picture>
Don't forget to include necessary links in the <head/>:
<link rel="preload" as="image" media="(-webkit-min-device-pixel-ratio: 3) and (-webkit-max-device-pixel-ratio: 3.9)" imagesrcset="...">
For fonts, prioritize modern formats like WOFF2, optimized for web use and widely supported.
Render delays can stem from main thread busyness, last-second DOM changes, or CSS blockages:
- Defer non-essential or third-party JS loading after the main document.
- Be aware that image decoding occurs on the main thread; prefer asynchronous decoding for non-critical images.
To avoid last-second changes affecting rendering latency, ensure the main content is fully loaded server-side or during build time.
CSS can block resources; consider inlining critical CSS in <head/> and deferring non-critical styles to enhance FCP and LCP metrics.
Modern browsers parse and render HTML progressively; optimize by placing LCP elements early in the document for improved LCP timings tailored to different viewport dimensions.
Final Say
To enhance web performance, the Largest Contentful Paint (LCP) must be understood and optimized. Users’ perception of a page as interactive is influenced by LCP, which has a direct impact on their experience. Web developers can greatly improve page load speeds and user engagement by concentrating on LCP optimization techniques, including controlling render delays, optimizing pictures and fonts, employing pre-connect directives, and prioritizing key resources. Putting these strategies into practice guarantees that users enjoy a smooth and effective browsing experience while also improving SEO metrics and general site usability.
FAQs on LCP Optimization
Which typical mistakes should one avoid when trying to optimize for LCP?
Delays in LCP can be avoided by limiting the usage of render-blocking CSS, large pictures, and blocking scripts. To reduce load times, make sure resources are appropriately scaled and compressed.
Does LCP optimization need to be technical?
Although there are technical nuances involved in some elements of LCP optimization, many tactics may be executed with a basic understanding of performance optimization and web development. Expert consultation and tool use can further expedite the process.
Does LCP optimization enhance user experience in addition to SEO benefits?
By speeding up information accessibility and cutting down on page load times, LCP optimization immediately improves user experience. As a result, conversion rates rise, engagement levels rise, and bounce rates decline.