For a good user experience, pages should be displayed as quickly as possible. Indeed, waiting for content to appear on the screen is a source of dissatisfaction for Internet users.
To assess the time needed for a page to display, First Contentful Paint (FCP) measures the time needed to render the initial DOM content, but does not capture the time needed to render the most important content in terms of size (generally the most relevant to users).
Largest Contentful Paint (LCP) is a Core Web Vitals metric that indicates when the largest piece of content becomes visible in the viewport. It can be used to determine when the page’s main content is displayed on screen.
In the following sections, we’ll look at the most common causes of poor LCP, and how to address them:
- Long server response times
- JavaScript and CSS blocking rendering
- Resources that take a long time to load
- Client-side rendering
(Editor’s note: we regularly feature techniques and tips to help you improve all your webperf metrics in our monthly newsletter, whichyou can subscribe to here).
Largest Contentful Paint and slow server response times
The longer it takes for a browser to receive content from the server, the longer it takes to display anything on the screen. Faster server response times directly improve every page load metric, including LCP.
First and foremost, improve how and where your server handles your content. Observe your Time to First Byte (TTFB) to measure your server’s response times.
You can improve your TTFB in a number of ways, which we’ll explain in detail below:
- Optimize your server
- Bring content closer to your users with a CDN
- Cacheyour resources
- Prioritize cached HTML content
- Make third-party connections fast
Optimize your server
Are you running expensive queries that take up a lot of your server’s time? Or are there other complex server-side operations that delay the arrival of content on the page? Analyzing and improving the efficiency of your server-sidecode will directly improve the time it takes for the browser to receive data.
Instead of immediately serving a static page in response to a browser request, many server-side frameworks need to create the web page dynamically. In other words, rather than simply sending a complete, ready-made HTML file when requested by the browser, frameworks must perform operations to build the page. This may be due to the pending results of a database query, or even the fact that components need to be generated in markup by a UI framework (such as React). Many frameworks that run on the server side offer recommendations for speeding up this process (here are a few to improve the performance of an overloaded server).
Use a CDN
A Content Delivery Network (CDN) is a network of servers located in different geographical areas. If your web page content is hosted on a single server, your website will load more slowly for users who are geographically remote, as their browser requests literally have to travel around the world. Consider using a CDN to ensure that your users don’t have to wait for network requests to remote servers.
Caching your resources
If your HTML code is static and doesn’t need to change with every request, caching can save you the trouble of recreating it unnecessarily. By storing a copy of the generated HTML code, server-side caching can reduce TTFB and resource usage.
Depending on your tools, there are many ways to apply server-side caching:
- configure a reverse proxy (Varnish, nginx) to serve cached content or act as a cache server when installed in front of an application server;
- configure and manage the cache behavior of your cloud provider (Firebase, AWS, Azure);
- use a CDN that provides edge servers so that your content is cached and stored as close as possible to your users.
Give priority to cached HTML pages
Once installed, a Service Worker runs in the browser’s background and can retrieve requests from the server. This programming of cache control allows all or part of the HTML page content to be cached, and the cache to be updated only when the content has changed.
The following graph shows how Largest Contentful Paint distributions have been reduced on one site using this technique:
Largest Contentful Paint distribution with and without Service Worker
The graph shows the LCP distribution for a single site over 28 days, segmented by Service Workerstatus . You’ll notice how many more pages have a better LCP after implementing a cache-first strategy for these pages via the Service Worker (blue part of the graph).
To find out more about techniques for serving cache-first HTML pages in full or in part, please consult this resource: Smaller HTML Payloads with Service Workers.
Establish third-party connections quickly
Server requests to third-party origins can also have an impact on LCP, especially if they are required to display critical content on the page. Use rel = “preconnect ” to inform the browser that your page intends to establish a connection as soon as possible.
[pastacode lang=”markup” manual=”%3Clink%20rel%3D%22preconnect%22%20href%3D%22https%3A%2F%2Fexample.com%22%3E” message=”” highlight=”” provider=”manual”/]
You can also use dns-prefetch for faster DNS resolutions.
[pastacode lang=”markup” manual=”%3Clink%20rel%3D%22dns-prefetch%22%20href%3D%22https%3A%2F%2Fexample.com%22%3E” message=”” highlight=”” provider=”manual”/]
Although these two hints work differently, you can use dns-prefetch as an alternative for browsers that don’t support preconnect.
[pastacode lang=”markup” manual=”%3Chead%3E%0A%C2%A0%E2%80%A6%0A%C2%A0%3Clink%20rel%3D%22preconnect%22%20href%3D%22https%3A%2F%2Fexample.com%22%3E%0A%C2%A0%3Clink%20rel%3D%22dns-prefetch%22%20href%3D%22https%3A%2F%2Fexample.com%22%3E%0A%3C%2Fhead%3E” message=”” highlight=”” provider=”manual”/]
For more information on this subject, please consult this resource: Establish network connections early to improve perceived page speed
Largest Contentful Paint: JavaScript and CSS that block rendering
Before a browser can render any content, it must parse the HTML markup in the DOM. The HTMLparser will stop if it encounters external style sheets(<link rel = “stylesheet”>) or synchronous JavaScript tags(<script src = “main.js”>).
Both scripts and stylesheets are render-blocking resources that delay FCP, and consequently LCP. Defer all non-critical JavaScript and CSS code to speed up the loading of your web page’s main content.
Reduce CSS blocking time
Ensure that only the minimum amount of CSS required blocks rendering on your site by applying the following techniques (Editor’s note: our engine canautomate some of these techniques):
- minimize CSS
- defer non-critical CSS
- inline critical CSS
Minimize CSS
To enhance readability, CSS files may contain elements such as spaces, indentations or comments… But these characters and spaces are useless to the browser, and minification removes them. Anything that minimizes CSS blocking improves the speed and time required to fully render the page’s main content (LCP).
If you’re using a bundle generator or buildtool , include an appropriate plugin to reduce CSS files on each build :
- for webpack: optimize-css-assets-webpack-plugin
- for Gulp: gulp-clean-css
- for Rollup: rollup-plugin-css-porter
For further information, please consult this guide: Minify CSS.
Deferring non-critical CSS
Use the Coveragetab in Chrome DevTools to detect all unused CSS on your web page.
Then, to optimize :
- Delete any unused CSS or move it to another style sheet if it’s used on a specific page of your site.
- For any CSS not required for initial rendering, use loadCSS and load files asynchronously using rel=”preload ” and onload.
[pastacode lang=”css” manual=”%3Clink%20rel%3D%22preload%22%20href%3D%22stylesheet.css%22%20as%3D%22style%22%20onload%3D%22this.rel%3D’stylesheet’%22%3E” message=”” highlight=”” provider=”manual”/]
Example of LCP enhancement: before and after deferring non-critical CSS
For more details on the subject, please consult this guide: Defer non-critical CSS.
Inline critical CSS
Inline critical path CSS used above the waterline by including it directly in the <head>tag .
Inline critical CSS
Inlining important styles reduces the need to go back and forth to retrieve critical CSS. Deferring the rest also reduces CSS blocking time.
If you can’t manually add inlined styles to your site, you can use a library to automate the process. Here are a few examples:
- Critical, CriticalCSS and Penthouse are packages that extract and inline CSS above the waterline.
- Critters is a webpack plugin that inline critical CSS and lazyloade the rest.
- Ndt: our engine also automates CSS optimization.
Example of LCP enhancement: before and after critical CSS inlining
To learn more about this subject, please consult this resource: Extract critical CSS.
Reducing JavaScript blocking time
Load and send the minimum amount of JS necessary to users. Reducing the amount of JS blocking translates into faster rendering, and therefore better Largest Contentful Paint.
This can be achieved by optimizing your scripts in a number of ways:
- Minimize and compress your JavaScriptfiles
- Defer unused JS
- Reduce unusedpolyfills
This article on FID optimization details techniques for reducing JS blocking time.
The impact of slow-loading resources on Largest Contentful Paint
While an increase in CSS or JavaScript blocking time directly results in a drop in performance, the time taken to load many other types of resource can also affect display speed. The families of elements that affect LCP are :
- <img> elements
- <image> elements within a <svg> element
- <video> elements (if specified, the posterimage is used to measure LCP)
- elements with a background image loaded via the url()function (as opposed to a CSS gradient)
- Block-levelelements containing text nodes or other inlinetext elements .
The time it takes to load these elements, if rendered above the waterline, will have a direct effect on LCP. There are a number of ways to ensure that these files are loaded as quickly as possible, which we will detail below:
- optimize and compress images
- preload important resources
- compressing text files
- adaptive serving
- caching resources using a Service Worker
Optimize and compress images
For many sites, images are the largest visible element once the page has finished loading.Heroimages, large carousels or banners are common examples.
The image is the largest element on the page (design.google)
Improving loading and rendering times for these types of images will directly speed up the LCP. To achieve this :
- Consider not using an image in the first place. If it’s not relevant to the content, delete it.
- Compress images (note: our engine automatically and intelligently optimizes images).
- Convert images to more recent formats (JPEG 2000, JPEG XR or WebP).
- Use responsive images.
- Consider using an image CDN.
Here’s a complete guide to image optimization: Optimize your images. (and here on how our engine resizes images).
Preload important resources
Sometimes, important resources that are declared or used in a given CSS or JavaScript file can be retrieved later than you’d like, such as a font deeply hidden in one of an application’s many CSS files.
If you know that a particular resource needs to be prioritized, use <link rel = “preload” > to retrieve it earlier. Different resources can be preloaded, but it’s in your best interest to focus on preloading critical resources, such as fonts, above-waterline media, critical-path CSS and JS.
[pastacode lang=”javascript” manual=”%3Clink%20rel%3D%22preload%22%20as%3D%22script%22%20href%3D%22script.js%22%3E%0A%3Clink%20rel%3D%22preload%22%20as%3D%22style%22%20href%3D%22style.css%22%3E%0A%3Clink%20rel%3D%22preload%22%20as%3D%22image%22%20href%3D%22img.png%22%3E%0A%3Clink%20rel%3D%22preload%22%20as%3D%22video%22%20href%3D%22vid.webm%22%20type%3D%22video%2Fwebm%22%3E%0A%3Clink%20rel%3D%22preload%22%20href%3D%22font.woff2%22%20as%3D%22font%22%20type%3D%22font%2Fwoff2%22%20crossorigin%3E” message=”” highlight=”” provider=”manual”/]
Since Chrome 73, preloading can be used with responsiveimages to combine the benefits and speed up image loading even further.
[pastacode lang=”markup” manual=”%3Clink%0A%20%20rel%3D%22preload%22%0A%20%20as%3D%22image%22%0A%20%20href%3D%22wolf.jpg%22%0A%20%20imagesrcset%3D%22wolf_400px.jpg%20400w%2C%20wolf_800px.jpg%20800w%2C%20wolf_1600px.jpg%201600w%22%0A%20%20imagesizes%3D%2250vw%22%0A%3E” message=”” highlight=”” provider=”manual”/]
Compressing text files
Compression algorithms, such as Gzip and Brotli, can significantly reduce the size of text files (HTML, CSS, JavaScript) as they are transferred between server and browser. Gzip is efficiently supported in all browsers and Brotli, which provides even better compression results, can be used on almost all recent browsers.
Compressing your resources will reduce their size, improving loading times and therefore LCP.
- First of all, check whether your server already automatically compresses files. Most hosting platforms, CDNs and reverse proxies encode resources with compression by default, or allow you to configure them easily.
- If you need to modify your server to compress files, consider using Brotli instead of gzip, as it can provide better compression rates .
- Once you’ve chosen a compression algorithm, compress resources in advance during the generation process rather than using them on the fly, as requested by the browser. This reduces server load and avoids request delays, especially when using high compression ratios.
Example of LCP enhancement: before and after Brotli compression
For more details on resource compression, please consult this guide: Minify and compress network payloads.
Adaptive serving
When loading resources that make up the main content of a page, it can be effective to conditionally retrieve different resources depending on the user’s device or network conditions. This can be done using the Network Information, Device Memory and HardwareConcurrencyAPIs .
If you have important resources that are essential for initial rendering, you can use different variants of the same resource depending on the user’s connection or device. For example, you can display an image instead of a video for any connection speed below 4G :
[pastacode lang=”javascript” manual=”if%20(navigator.connection%20%26%26%20navigator.connection.effectiveType)%20%7B%0A%C2%A0if%20(navigator.connection.effectiveType%20%3D%3D%3D%20’4g’)%20%7B%0A%C2%A0%C2%A0%C2%A0%2F%2F%20Load%20video%0A%C2%A0%7D%20else%20%7B%0A%C2%A0%C2%A0%C2%A0%2F%2F%20Load%20image%0A%C2%A0%7D%0A%7D” message=”” highlight=”” provider=”manual”/]
Here is a list of properties you can use:
- navigator.connection.effectiveType
- navigator.connection.saveData (enable / disable data saver)
- navigator.hardwareConcurrency (CPU)
- navigator.deviceMemory
For more information onadaptive serving, please consult this resource: Adaptive serving based on network quality.
Resource caching using a Service Worker
Service Workers can be used for many tasks, including serving smaller HTML responses, as mentioned above. They can also be used to cache any static resource that can be served to the browser rather than from the network with repeated requests.
Pre-caching critical resources using a Service Worker can dramatically reduce their load times, especially for users who reload the web page with a weaker connection (or even offline). Libraries such as Workbox can make the process of updating cached resources much easier than designing a customService Worker to handle it yourself.
For more information,see this resource : Network reliability.
Client-side rendering and Largest Contentful Paint optimization
Many sites use client-side JS to display pages directly in the browser. Frameworks and libraries such as React, Angular and Vue have facilitated the creation of Single Page Applications that manage the various facets of a web page entirely client-side, rather than server-side.
If you’re creating a site that is primarily rendered client-side, you need to be wary of the effect this can have on the LCP if a large JavaScriptbundle is used. If optimizations are not in place to prevent this, users may not see or interact with page content until all critical JavaScript has been downloaded and executed.
When creating a client-side rendered site, consider the following optimizations :
- Reduce critical JavaScript
- Use server-side rendering
- Use pre-rendering
Reduce critical JavaScript
If the content of your site only becomes visible or active after a certain amount of JavaScript has been downloaded, it’s even more important to reduce the size of your bundleas much as possible . This can be achieved using the following techniques:
- Minimizing JavaScript
- Deferring unused JavaScript
- Reducing unusedpolyfills
Server-side rendering
Reducing the amount of JavaScript should always be a priority for sites that are primarily rendered client-side. However, you should also consider combining server-side rendering to improve LCP as much as possible.
This concept works by using the server to render the application in HTML, where the client thenhydrates the JavaScript and requested data onto the same DOM content. This can improve LCP by ensuring that the main content of the page is rendered first on the server rather than only client-side, but there are a few drawbacks:
- Maintaining the same JavaScript-rendered application on both server and client sides can increase complexity.
- Running JavaScript to render an HTML file on the server will always increase server response times (TTFB) compared to simply serving static pages from the server.
- A page rendered by the server may look interactive, but it can’t respond to any user input until all client-side JavaScript has been executed. In short, this can degrade Time to Interactive (TTI).
Use pre-rendering
Pre-rendering is a separate technique which is less complex than Server-side rendering , and which also improves LCP. A headlessbrowser – with no user interface – is used to generate static HTML files corresponding to each route at build time. These files can then be sent along with the necessary JavaScriptbundles .
With pre-rendering, Time To Interactive is inevitably affected, but server response times are not as much as with a server-side rendering solution, which dynamically renders each page only after it has been requested.
Example of LCP improvement: before and after pre-rendering
To find out more about server-sidearchitectures , take a look at this resource: Rendering on the web.
Developer tools for optimizing Largest Contentful Paint
Numerous tools exist to measure and improve LCP:
- Lighthouse lets you measure LCP (as well as PageSpeed Insights):
- The Timings section of the Performance panel in Chrome DevTools includes an LCP marker and indicates which element is associated with LCP when you hover over the associatedNode .
- Chrome User Experience Report offers LCP values from real-life conditions and aggregated for a given site.
Read also: