Written by Harry Roberts on CSS Wizardry.
Desk of Contents
- Remedy Every thing Beforehand
- Optimise Your LCP Candidate
- Keep away from Picture-Based mostly LCPs
- Use the Greatest Candidate
- Don’t Shoot Your self within the Foot
Largest Contentful Paint (LCP) is my favorite Core Internet
Important. It’s the simplest to optimise, and it’s the one one of many three that
works the very same within the lab because it does within the area (don’t even get me
began on this…). But, surprisingly, it’s the least optimised CWV in CrUX—at
the time of writing, solely half of origins within the dataset had a Good LCP:
As soon as extra, we noticed an
enhance within the variety of origins having good Core Internet Vitals (CWV) pushed by
improved good CLS.
52.7% of origins had good LCP
94.9% of origins had
70.6% of origins had good CLS
39.0% of origins had good LCP, FID,
— Chrome UX Report 📊 (@ChromeUXReport) 8 March
This genuinely surprises me, as a result of LCP is the best metric to enhance. So,
on this submit, I wish to go deep and present you some fascinating methods and
optimisations, in addition to some pitfalls and bugs, beginning with some quite simple
Remedy Every thing Beforehand
Let’s begin with the simple stuff. LCP is a milestone timing—it measures…
…the render time of the biggest picture or textual content block seen inside the
viewport, relative to when the web page first began loading.
The necessary factor to notice right here is that Google doesn’t care the way you get to LCP,
so long as you get there quick. There are a variety of different issues that would occur
between the beginning of the web page load lifecycle and its LCP. These embrace (however are
not restricted to):
- DNS, TCP, TLS negotiation
- First Paint
- First Contentful Paint
If any of those are gradual, you’re already on the again foot, and so they’re going to
have a knock-on impact in your LCP. The metrics above don’t matter in and of
themselves, but it surely’s going to assist your LCP if you may get them as little as
An analogy I exploit with non-technical stakeholders goes slightly like this:
It’s worthwhile to get the youngsters to high school for 08:30. That’s all the varsity cares
about—that the youngsters are there on time. You are able to do loads to assist make this
occur: put together their garments the night time earlier than; put together their lunches the night time
earlier than (do the identical for your self). Set acceptable alarms. Have a morning
routine that everybody follows. Depart the home with loads of time to spare.
Plan in appropriate buffer time for site visitors points, and so on.
The varsity doesn’t care for those who laid out uniforms the night time earlier than. You might be being
judged in your means to get the youngsters to high school on time; it’s simply frequent sense
to do as a lot as you’ll be able to to make that occur.
Similar together with your LCP. Google doesn’t (at present) care about your TTFB, however a very good
TTFB goes to assist get nearer to a very good LCP.
Optimise your complete chain. Be sure you get the whole lot beforehand as quick as
potential so that you simply’re arrange for fulfillment.
Optimise Your LCP Candidate
A tip that hopefully doesn’t want me to enter any actual element: if in case you have an
image-based LCP, make sure that it’s properly optimised—appropriate format, appropriately
sized, sensibly compressed, and so on. Don’t have a 3MB TIFF as your LCP candidate.
Keep away from Picture-Based mostly LCPs
This isn’t going to work for lots, if not most, websites. However the easiest way to get
a quick LCP is to make sure that your LCP is text-based. This, in impact, makes your
FCP and LCP synonymous. That’s it. So simple as that. If potential, keep away from
image-based LCP candidates and decide as an alternative for textual LCPs.
The possibilities are, nonetheless, that received’t give you the results you want. Let’s take a look at our different
Use the Greatest Candidate
Okay. Now we’re entering into the enjoyable stuff. Let’s take a look at which LCP candidates
we have now, and whether or not there are any relative deserves to every.
There are a number of potential candidates in your LCP. Taken straight from
net.dev’s Largest Contentful Paint (LCP) web page, these
<picture>components inside an
<video>components (the poster picture is used)
- A component with a background picture loaded through the
against a CSS
components containing textual content nodes or different inline-level textual content components kids.
For the needs of this text, I constructed a collection of lowered demos displaying how
every of the LCP sorts behave. Every of the demos additionally accommodates a reference to
a blocking in-
- exaggerate the waterfalls, and;
- stall the parser to see if or how every LCP sort is impacted by the preload
It’s additionally price noting that every demo may be very stripped again, and doesn’t
essentially characterize real looking circumstances through which many responses could be
in-flight on the identical time. As soon as we run into useful resource rivalry, LCP
candidates’ discovery may go otherwise to what’s exhibited in these lowered
check circumstances. In circumstances like these, we’d look to Precedence
Preload to help. All I’m
eager about proper now’s inherent variations in how browsers deal with sure
The preliminary demos could be discovered at:
is offered so that you can look by, although we’ll choose aside particular person
waterfalls later within the article. That every one comes out wanting like this:
poster are an identical in LCP;
<svg> is the
subsequent quickest, though there’s a bug within the LCP time that Chrome studies;
background-image-based LCPs are notably the slowest.
As we will see, not all candidates are born equal. Let’s take a look at every in
Of the image-based LCPs, that is most likely our favorite.
<img> components, as
lengthy as we don’t mess issues up, are fast to be found by the preload
and as such, could be requested in parallel to previous—even blocking—assets.
It’s price noting that the
<image> factor behaves the identical means because the
<img factor. For this reason you might want to write a lot verbose syntax in your
sizes attributes: the thought is that you simply give the browser sufficient
details about the picture that it could possibly request the related file through the
and never have to attend till structure. (Though, I suppose—technically—there should be
like just a few milliseconds compute overhead figuring out which mixture of
sizes to make use of, however that will likely be mooted fairly shortly
by just about some other shifting half alongside the best way.)
<picture> components outlined in
<svg>s show two very fascinating behaviours.
The primary of which is a straightforward bug through which Chrome misreports the LCP candidate,
seemingly overlooking the
<picture> completely. Relying in your context, this
may imply far more beneficial and optimistic LCP scores.
As soon as the repair rolls out in M102 (which is Canary on the time of writing, and can
attain Secure on 24 Could, 2022), we
can anticipate correct measurements. This does imply that you could be expertise
degraded LCP scores in your website.
Due to the present reporting bug,
<svg> is prone to go from
being (inadvertently) one of many quickest LCP sorts, to one of many slowest. In
the unlikely occasion that you’re utilizing
<svg>, it’s most likely
one thing that you simply wish to verify on sooner moderately than later—your scores are
prone to change.
The bug pertains solely to reported LCP candidate, and doesn’t impression how the
browser really offers with the assets. To that finish, waterfalls in all Chrome
variations look an identical, and networking/scheduling behaviour stays unchanged.
Which brings me onto the second fascinating factor I noticed with
<picture> components outlined in
<svg>s look like hidden from the preload
scanner: that’s to say, the
href attribute will not be parsed till the browser’s
major parser encounters it. I can solely guess that that is just because the
preload scanner is constructed to scan HTML and never SVG, and that that is by design
moderately than an oversight. Maybe an optimisation that Chrome may make is to
preload scan embedded SVG in HTML…? However I’m certain that’s far more simply mentioned
than carried out…
I’m pleasantly shocked by the behaviour exhibited by the
attribute. It appears to behave identically to the
<img /> factor, and is
found early by the preload scanner.
Which means that
poster LCPs are inherently fairly quick, in order that’s good
The opposite information is that it appears to be like like there’s intent to take the primary body of
a video because the
LCP candidate if no
poster is current. That’s going to be a troublesome LCP to
get underneath 2.5s, so both don’t have a
<video> LCP in any respect, or ensure you
begin utilizing a
poster picture with it.
Sources outlined in CSS (mainly something requested through the
perform) are gradual by
default. The commonest candidates listed here are background photographs and net fonts.
The rationale these assets (on this particular case, background photographs) are gradual
is as a result of they aren’t requested till the browser is able to paint the DOM
node that wants them. You’ll be able to learn extra about that on this Twitter thread:
Easy but important
factor all builders ought to remember: CSS assets (fonts, background
photographs) are usually not requested by your CSS, however by the DOM node that wants them
[Note: slight oversimplification, but the correct way to think about
— Harry Roberts (@csswizardry) 10 September
Which means that
background-image LCPs are requested on the final second,
which is way too late. We don’t like
Should you at present have a website whose LCP is a
background-image, you could be
considering of refactoring or rebuilding that element proper now. However, fortunately,
there’s a really fast workaround that requires virtually zero effort: let’s
complement the background with a hidden
<img /> that the browser can uncover
a lot earlier.
<div fashion="background-image: url(lcp.jpg)"> <img src="lcp.jpg" alt="" width="0" top="0" fashion="show: none !necessary;" /> </div>
This little hack permits the preload scanner to choose up the picture, moderately than
ready till the browser is about to render the
<div>. This got here in 1.058s
sooner than the naive
background-image implementation. You’ll discover that this
waterfall virtually precisely mimics the quickest
<img /> possibility:
We may additionally
preload this picture, moderately than utilizing an
<img /> factor, however
I usually really feel that
preload is a little bit of a code odor and must be averted
- text-based LCPs are virtually at all times going to be the quickest;
posterLCPs are good and quick, discoverable by the preload
<video>and not using a
postermay need its first body thought-about as an LCP
candidate in future variations of Chrome;
<svg>is at present misreported however is gradual as a result of the
is hidden from the preload scanner;
background-images are gradual by default, due to how CSS works;
- we will sidestep this problem by including an invisible
- we will sidestep this problem by including an invisible
Alright! Now we all know that are the perfect candidates, is there anything can
do (or keep away from doing) to ensure we aren’t working slowly? It turns on the market
are loads of issues that people do which inadvertently maintain again LCP scores.
Don’t Lazy-Load Your LCP
Each time I see this, my coronary heart sinks slightly. Lazy-loading your LCP is
fully counter-intuitive. Please don’t do it!
Curiously, one of many options of
loading="lazy" is that it hides the
picture in query from the preload
Which means that, even when the picture is within the viewport, the browser will nonetheless
late-request it. For this reason you’ll be able to’t safely add
loading="lazy" to all of
your photographs and easily hope the browser does (what you assume is) the fitting
In my assessments, lazily loading our picture pushed LCP again to 4.418s: 1.274s slower
<img /> variant, and virtually an identical to the
Don’t Fade-In Your LCP
Predictably, fading in our picture over 500ms pushes our LCP occasion again by 500ms.
Chrome takes the top of the animation interval because the LCP measurement, shifting us
to a 3.767s LCP occasion moderately than 3.144s.
Keep away from fading in your LCP candidate, whether or not it’s image- or text-based.
Don’t Host Your LCP Off-Website
The place potential, we must always at all times self-host our static
contains our LCP candidate.
It’s not unusual for website homeowners to make use of third-party picture optimisation providers
reminiscent of Cloudinary to serve each automated and
dynamically optimised photographs: on the fly resizing, format switching,
compression, and so on. Nevertheless, even when considering the efficiency
enhancements of of those providers, the price of heading to a distinct origin
virtually at all times outweighs the advantages. In
the time spent resolving a brand new origin added 509ms to general time spend
downloading our LCP picture.
By all means, use third occasion providers for non-critical, non-LCP photographs, but when
you’ll be able to, deliver your LCP candidate onto the identical origin because the host web page. That’s
precisely what I do for this website.
preconnect might assist slightly, it’s nonetheless extremely unlikely
to be sooner than not opening a brand new connection in any respect.
Don’t Construct Your LCP on the Consumer
I see this all too typically, and it’s a part of the continued obsession with
reference to the LCP candidate (ideally an
<img /> factor) will likely be proper
there instantly. Nevertheless, for those who construct your LCP candidate with JS, the method
is far, far more drawn out.
Constructing your LCP candidate in JS may vary from a easy JS-based
picture gallery, proper the best way by to a totally client-rendered web page. The beneath
waterfall reveals the latter:
The primary response is the HTML. What we’d wish to have is an
<img /> proper
there within the markup, ready to be found virtually instantly. As a substitute, the
HTML requests a
framework.js at entry 12. This, in flip, ultimately
requests API knowledge in regards to the present product, at entry 50. This response accommodates
details about associated product imagery, which is ultimately put into the
digital DOM as an
<img />, lastly initiating a request for the LCP candidate
at entry 53, properly over 7s into the web page load lifecycle.
Don’t Usurp Your Personal LCP
This one breaks my coronary heart each time I see it… Don’t late-load any content material that
by accident turns into your LCP candidate. Often, these are issues like cookie
banners or e-newsletter modals that cowl content material and get flagged as a really late
LCP. I mocked up a late-loading modal for our assessments, and what’s necessary to
keep in mind is that the rating is correct, simply not what we hope for:
Be sure that your LCP candidate is what you anticipate it to be. Design modals and
cookie banners and so on. to:
- load instantly, and;
- not really be your largest piece of content material.
Alright. We lined quite a bit there, however the takeaway is fairly easy:
text-based LCPs are the quickest, however unlikely to be potential for many. Of
the picture based mostly LCP sorts,
<img /> and
poster are the quickest.
<picture>s outlined in
<svg>s are gradual as a result of they’re hidden from the
preload scanner. Past that, there are a number of issues that we have to keep away from:
don’t lazy load your LCP candidate, and don’t construct your LCP in JS.