Sunday, October 5, 2025
HomeCSSThe Final Low-High quality Picture Placeholder Approach – Harry Roberts – Net...

The Final Low-High quality Picture Placeholder Approach – Harry Roberts – Net Efficiency Advisor


Written by on CSS Wizardry.

Desk of Contents
  1. Low-High quality Picture Placeholders
  2. Core Net Vitals and Largest Contentful Paint
  3. Largest Contentful Paint Caveats
  4. Don’t Upscale Your LQIP
    1. Calculating the Upscaling Penalty
  5. Intention for a Minimal of 0.05BPP
  6. LQIP and BPP Calculator
  7. Implementing Low-High quality Picture Placeholders
    1. Use an Picture Transformation Service
    2. Use Your Judgement
  8. Abstract

On the time of writing,
99.9% of pages on the
internet embody no less than one picture. The median image-weight per web page landed at
881KB in 2022,
which is greater than HTML, CSS, JS, and fonts mixed! And whereas pictures don’t
block rendering (until you do one thing
foolish
), it’s
vital to think about how we provide a fairly nice expertise whereas customers
are ready for pictures to load. One answer to that downside is Low-High quality
Picture Placeholders
.

Low-High quality Picture Placeholders

Low-High quality Picture Placeholders are nothing new. Man
Podjarny
is accountable, I suppose for coining the
time period over a decade
in the past
! And
earlier than that, we even had the lowsrc attribute for <img> components:

<img lowsrc=lo-res.jpg src=hi-res.jpg alt>

I want we’d by no means deprecated
lowsrc
—it
would have saved us a lot problem in the long term.

The approach is easy: as pictures are usually heavier and slower assets,
and so they don’t block rendering, we must always try to offer customers one thing to
take a look at whereas they look forward to the picture to reach. The answer? Present them
a low-quality picture placeholder, or LQIP.

The upshot is that the consumer is aware of that one thing is occurring, and, ideally,
they need to have roughly some thought what is occurring—in any case, we wish our
LQIP to considerably resemble the ultimate picture.

Core Net Vitals and Largest Contentful Paint

Whereas LQIP isn’t a brand new topic in any respect, Core Net
Vitals

and Largest Contentful
Paint

are, and sadly, they don’t essentially get alongside so effectively…

In case your LCP candidate is a picture (whether or not that’s a background-image or an
<img> aspect), it’s going to be considerably slower than in case your LCP candidate
was a textual content node, and whereas making image-based LCPs
quick

isn’t not possible, it’s tougher.

Utilizing an LQIP whereas we look forward to our full-res LCP candidate actually fills
a user-experience hole, however, owing to sure guidelines and restrictions with LCP as
a spec (extra on that later), it’s unlikely to assist our LCP scores.

When the complete decision picture ultimately arrives, it’s possible that that picture
might be counted as your LCP, and never your LQIP:

It will be good to have a state of affairs whereby your LQIP does meet necessities
for consideration as LCP, resulting in sub-2.5s scores, but additionally load in a excessive
decision quickly after, thus enhancing the consumer expertise. The most effective of each
worlds:

Is that even attainable? Let’s discover out…

Largest Contentful Paint Caveats

There may be some vital nuance that we must always concentrate on earlier than we go any
additional. There are fairly just a few transferring components on the subject of how and when your
LCP candidates are captured, once they’re up to date, and which candidate is
finally used.

Chrome retains taking new LCP candidates proper up till a consumer interacts with the
web page. Because of this if an <h1> is seen instantly, a consumer scrolls, then
a bigger <img> arrives moments after, the <h1> is your LCP aspect for that
web page. If a consumer doesn’t work together in that brief window, a brand new entry is captured,
and now the <img> is your LCP aspect. Discover under how our <h1> is
momentarily thought-about our LCP candidate at 1.0s, earlier than finally being
changed by the <img> at 2.5s:

Blue shading exhibits an LCP candidate; inexperienced shading and/or a purple
border exhibits the precise LCP aspect and occasion. (View full
dimension)

The important thing takeaway right here is that Chrome retains in search of new LCP candidates,
and the second it finds something bigger, it makes use of that.

What if Chrome finds a later aspect of the identical dimension? Fortunately, Chrome will
not think about new components of the identical dimension because the beforehand reported LCP
candidate. That protects us in conditions like this:

Issues like picture grids are measured on their first picture, not their
final. That is nice information. (View full
dimension)

Notice that at 1.4s we get our LCP occasion in full. When the opposite eight pictures
arrive at 2.0s, they make no distinction to our rating.

This all appears easy sufficient—Chrome retains on in search of the biggest
aspect after which makes use of that, proper? And it doesn’t essentially spell unhealthy information for
our LQIP both. So long as our closing picture is similar dimensions because the LQIP
was…?

Not fairly. There’s some delicate complexity designed to stop folks gaming the
system, which is precisely what we’re making an attempt to do.

Warning: It’s crucial that you just nonetheless
present an awesome consumer expertise. Passing LCP for metrics’ sake is unwise and
towards the spirit of internet efficiency. Be certain that your LQIP remains to be of
adequate high quality to be helpful, and comply with it up instantly along with your
full-quality picture. Poor high quality pictures, notably the place ecommerce is
involved, are particularly
dangerous
.

Don’t Upscale Your LQIP

Every picture within the exams thus far has been a 200×200px <img> displayed at
200×200px:

<img src=https://dummyimage.com/200/000/fff.png?2&textual content=200@200
     width=200 top=200 alt>

Which is that this, coming at 2KB:

What if we modify the <img> to 100×100px displayed at 200×200px, or
upscaled?

<img src=https://dummyimage.com/100/000/fff.png?4&textual content=100@200
     width=200 top=200 alt>

Which is available in at 1.4KB:

Already, you may see the loss in high quality related to upscaling this
picture.

Upscaled pictures might be discounted towards higher-resolution ones. (View full dimension)

Above, we see that we log a candidate at 1.5s, however the second picture at
2.0s turns into our LCP regardless of being rendered at the very same dimension!

And there’s the nuance. Chrome doesn’t need to reward a poor expertise, so
merely serving a tiny picture and displaying it a lot bigger won’t assist your LCP
scores if a denser picture turns up afterward. And I agree with this resolution, for
essentially the most half.

The primary takeaway is: don’t upscale your LQIP.

Calculating the Upscaling Penalty

Let’s get a bit extra detailed about upscaling and penalties. Some shut studying
of the spec

tells us precisely how this works. It’s not the simplest factor to digest, however I’ll
do my greatest to distil it for you right here. The reported space of your LCP aspect is
calculated as:

space = dimension × penaltyFactor

The place:

  • dimension is the realm of the LCP candidate presently within the viewport and never
    cropped or off-screen.
  • penaltyFactor is the issue by which upscaling will depend towards us,
    given by min(displaySize, naturalSize) / displaySize, the place:

    • naturalSize is the pixel space of the picture file in query.
    • displaySize is the pixel space that the picture might be rendered,
      no matter how a lot of it’s presently on-screen.

In full:

space = dimension × min(displaySize, naturalSize) / displaySize

Think about we took a big panorama picture, downscaled it to a predetermined
top, after which displayed it, cropped, as a sq.:

Within the above diagram, a is naturalSize, b is displaySize, and c is
dimension.

For the sake of ease, let’s assume your LCP candidate is at all times absolutely on-screen,
in-viewport, and never cropped (you probably have recognized and predictable cropping or
off-screen picture knowledge, you may regulate your maths accordingly). Because of this
dimension and displaySize at the moment are synonymous.

Let’s say we’ve got a 400×400px picture that’s downscaled to 200×200px. Its
space can be calculated as:

200 × 200 × min(200 × 200, 400 × 400) / (200 × 200) = 40,000

Thus the LCP’s reported dimension can be 40,000px2:

(View full dimension)

If we have been to make use of a 100×100px picture and upscale it to 200×200px, our
equation seems a bit of completely different:

200 × 200 × min(200 × 200, 100 × 100) / (200 × 200) = 10,000

(View full dimension)

This picture’s reported space is considerably smaller, regardless of being rendered at
the very same dimension! Because of this any subsequent pictures of a better high quality
might effectively steal our LCP rating away from this one and to a a lot later time.

Even when we used a 199×199px LQIP, we’d nonetheless register a brand new LCP the second our
full high quality picture arrives:

200 × 200 × min(200 × 200, 199 × 199) / (200 × 200) = 39,601

That every one received fairly tutorial, however my recommendation is principally: if you need your
LQIP to be thought-about as your LCP, don’t upscale it.
If you happen to do upscale it,
your reported space will come again smaller than you may count on, and thus the
later, excessive decision picture is more likely to ‘steal’ the LCP rating.

N.B. Fortunately, not one of the specs take gadget pixels or pixel
densities under consideration. It’s CSS pixels all the best way down.

Intention for a Minimal of 0.05BPP

The second restriction we have to get round is the lately
introduced

bits per pixel (BPP) threshold. Once more, to cease folks gaming the system, Chrome
determined that solely pictures of a sure high quality (or entropy) might be thought-about
as your LCP aspect. This prevents folks utilizing extremely low high quality pictures in
order to register a quick LCP time:

That heuristic reductions paints which aren’t contentful, however simply function
backgrounds or placeholders for different content material.

This alteration extends that heuristic to different pictures as effectively, when these pictures
have little or no content material, when in comparison with the dimensions at which they’re
displayed.
Largest Contentful Paint change in Chrome 112 to disregard low-entropy pictures

This one is way easier to make sense of. To ensure that a picture to be counted
as an LCP candidate, it must comprise no less than 0.05 bits of knowledge per pixel
displayed.

Notice that this is applicable to the picture’s displayed dimension and never its pure dimension:

Controls whether or not LCP calculations ought to exclude low-entropy pictures. If
enabled, then the related parameter units the cutoff, expressed because the
minimal variety of bits of encoded picture knowledge used to encode every rendered
pixel. Notice that this isn’t simply pixels of decoded picture knowledge; the rendered
dimension consists of any scaling utilized by the rendering engine to show the
content material.

options.cc

A 200×200px picture has 40,000 pixels. If we want 0.05 bits of knowledge for every
pixel, the picture must be no less than 2,000 bits in dimension. To get that determine in
Kilobytes, we merely have to divide it by 8,000: 0.25KB. That’s tiny!

A 1024×768px picture?

(1024 × 768 × 0.05) / 8000 = 4.9152KB

720×360px?

(720 × 360 × 0.05) / 8000 = 1.62KB

That was a lot much less tutorial, however my recommendation is principally: if you need your
LQIP to ever be thought-about as your LCP, make sure that it incorporates sufficient knowledge
.

To err on the facet of warning, I’m going by a BPP determine of 0.055. Actually, the
filesizes you’re aiming for are so small at this level that you just’ll in all probability
wrestle to get as little as 0.055BPP anyway, however it simply appears smart to construct in
10% of buffer in case any intermediaries try and compress your pictures
additional. (This could truly be not possible since you’re serving your
pictures over HTTPS, proper?)

LQIP and BPP Calculator

That’s a whole lot of specs and numbers. Let’s attempt make all of it a bit of simpler. I’ve
constructed this simplified calculator that will help you work out the mathematically
smallest attainable LCP candidate. It’s this picture that turns into your LQIP.

Your LQIP must be 1,440×810px
(1,166,400px2), and may have
a filesize no smaller than 8.019KB.

Utilizing the very same calculator you’re enjoying with proper now, I plugged in my
homepage’s
numbers and rebuilt my LCP. I managed to get my LQIP–LCP all the way down to
simply 1.1s on a 3G connection.

Notice that my <h1> and a <p>
are initially flagged as candidates earlier than Chrome lastly settles on the picture. (View
full dimension)

And from a chilly cache, over prepare wifi as I used to be penning this submit, I received a 2.1s
LCP rating on desktop!

(View full
dimension)

Implementing Low-High quality Picture Placeholders

My implementation turns into extremely easy as I’m utilizing a background picture.
This implies I can merely layer up the progressively higher-resolution recordsdata utilizing
CSS’ a number of backgrounds:

<head>

  ...

  <hyperlink rel=preload as=picture href=lo-res.jpg fetchpriority=excessive>

  ...

</head>
<physique>

  <header fashion="background-image: url(hi-res.jpg),
                                   url(lo-res.jpg)">
    ...
  </header>

</physique>
  1. As background-image is hidden from the preload
    scanner
    ,
    I’m preloading the LQIP (lo-res.jpg) in order that it’s already on its method
    earlier than the parser encounters the <header>.

    • Notice that I’m not preloading hi-res.jpg—we don’t need the 2 pictures to
      race one another, we wish them to reach one after the opposite.
  2. As soon as the parser reaches the <header>, the request for hi-res.jpg is
    dispatched.

    • At this level, if it’s absolutely fetched, we will render lo-res.jpg because the
      <header>’s background.
    • If lo-res.jpg isn’t prepared but, we’d fall again to a background-color or
      related whereas we wait.
  3. As lo-res.jpg is assured to reach first (it was requested a lot earlier
    and is way smaller in file-size), it will get displayed first.
  4. As soon as hi-res.jpg arrives, every time which may be, it takes the place of
    lo-res.jpg, switching out routinely.

My very particular
implementation

is extra advanced and nuanced than that (it’s responsive and I additionally use a brilliant
low-resolution Base64 placeholder that’s far too small to be thought-about an LCP
candidate), however that’s the principle approach in just a few strains. My layers seem like
this:

(View full dimension)
  1. The very first body is 810 bytes of 16×11px Base64 picture, far too
    small to qualify for LCP, and massively upscaled:
  2. The second body is a 24KB
    picture
    that’s each
    my LQIP and my LCP.
  3. The third and closing body is the full-resolution, 160KB
    picture
    .

The background-image methodology solely works if pictures are decorational. In case your
picture is content material (e.g. it’s a product picture), then semantically,
a background-image gained’t be adequate. On this case, you’ll in all probability find yourself
completely positioning some <img> components, however it’s additionally value noting that
you may apply background-images to <img>s, so the approach I take advantage of might be
kind of equivalent. One thing like this:

<head>

  ...

  <hyperlink rel=preload as=picture href=lo-res.jpg fetchpriority=excessive>

  ...

</head>
<physique>

  <img src=hi-res.jpg
       alt="Applicable alternate textual content"
       width=360
       top=360
       fashion="background-image: url(lo-res.jpg)">

</physique>

In reality, I do precisely that with the photograph of me within the
sidebar
.

Use an Picture Transformation Service

Being so tightly certain to those figures isn’t very redesign-friendly—you’d have
to reprocess your total picture library should you made your LCP candidate any
larger. With this in thoughts, I wouldn’t suggest trying this manually, or
batch-processing your total again catalogue.

As a substitute, use a service like Cloudinary to dimension and
compress pictures on the fly. This fashion, you solely want to revamp a handful of
elements and let Cloudinary do the remaining on demand. They make obtainable a
high quality
parameter

that takes a quantity which is a worth between 1 (smallest file dimension attainable)
and 100 (greatest visible high quality)
. E.g. q_80. Notice that this quantity will not be
a proportion.

To get your BPP all the way down to roughly 0.05, you’re going to need to experiment with
a actually small quantity. Mess around with quite a few completely different pictures out of your
web site to make sure no matter high quality setting you select doesn’t ever take you under
0.05BPP.

Use Your Judgement

If you happen to do handle to get your picture all the best way all the way down to your goal filesize,
there’s each probability it will likely be too low high quality to be visually acceptable,
even when it does fulfill LCP’s technical necessities.

Right here’s a present shopper’s product picture compressed all the way down to 4KB (their goal was
truly 3.015KB, however even essentially the most aggressive settings couldn’t get me all of the
method):


That is visually unacceptable as an LCP candidate, although it ticks each
field within the spec. My recommendation right here—and it’s very subjective—is that you just shouldn’t
settle for an LQIP–LCP that you just wouldn’t be joyful for a consumer to have a look at for any
time period.

On this specific occasion, I bumped the standard as much as 10, which got here in at
12KB, was nonetheless tremendous quick, however was visually way more acceptable.


Abstract

Of their makes an attempt to stop folks gaming the system, spec writers have needed to
outline precisely what that system is. Paradoxically, codifying these constraints
makes gaming the system a lot simpler, so long as you may be bothered to learn
the specs (which, fortunately for you, I’ve).

Largest Contentful Paint candidates are penalised for upscaling and in addition for low
entropy. By understanding how the upscaling algorithm works, and
calculate goal filesizes from enter dimensions, we will generate the smallest
attainable authentic LCP picture which can be utilized as a low-quality placeholder
whereas we look forward to our full-resolution picture to reach. The most effective of each worlds.



Did this assist? We will do far more!



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments