LQIP vs BlurHash Placeholders: Choosing an Image Placeholder

This comparison sits within Image Decoding & Placeholders, part of Image & Media Optimization. Placeholders fill the space an image will occupy while it loads. Their job is perceptual — make the page look composed rather than full of holes — and structural — reserve space so nothing shifts when the image arrives. They do not make the real image load faster, and badly chosen placeholders can make pages slower.

There are four common techniques. A dominant colour is a single background colour extracted from the image. LQIP (low-quality image placeholder) is a tiny version of the image — often 20–40 pixels wide — inlined as a data URI and blurred with CSS. BlurHash encodes a blurred representation into a 20–30 character string, decoded to pixels by JavaScript. ThumbHash is a newer variant with better colour and alpha fidelity in a similar size. Each trades bytes, JavaScript and fidelity differently.

Placeholder techniques compared Comparison of dominant colour, LQIP, BlurHash and ThumbHash by bytes in HTML, JavaScript needed, fidelity and LCP risk. Placeholder techniques compared Technique Bytes per image JS needed Fidelity Dominant colour ~10 bytes CSS none flat colour LQIP (data URI) 300-1500 bytes none composition visible BlurHash ~30 chars decoder + canvas soft blur ThumbHash ~30 bytes decoder better colour/alpha

Rapid Diagnosis

  • Measure placeholder bytes in HTML. Search the HTML for data:image; sum sizes. Hundreds of LQIPs can add tens of kilobytes.
  • Check placeholder JavaScript. BlurHash/ThumbHash decoders and the canvas work to render them run on the main thread; check whether they run at startup.
  • Check LCP attribution. If LCP fires early on a blurry preview and then again on the real image, the placeholder is acting as an LCP candidate.
  • Check CLS. Placeholders without the image's aspect ratio shift when replaced.

Root Cause Analysis

1. LQIP inflating HTML. Inlining a data URI for every grid image makes the HTML — which carries the LCP text and critical CSS — larger and slower.

2. Runtime decoders at startup. Decoding dozens of BlurHashes to canvas during load adds main-thread work right when INP and TBT matter.

3. Placeholders as LCP candidates. A visible <img> LQIP large enough to be the biggest element is recorded as an LCP candidate; LCP looks fast in the lab, but when the real image replaces it, a later LCP entry wins.

4. Unsized placeholders. Placeholder and image with different boxes produce layout shift.

Placeholder cost on a 40-card listing page Bar chart of HTML bytes and startup main-thread time added by four placeholder techniques on a forty-card listing page. Placeholder cost on a 40-card listing page Dominant colour (KB HTML) 0.4 LQIP all cards (KB HTML) 38 BlurHash strings (KB HTML) 1.2 BlurHash decode (ms main thread) 85

Step-by-Step: Implementing Placeholders Well

1. Default to aspect ratio plus dominant colour

html
<div class="card-media" style="--ph:#c9b8a4">
  <img src="/img/p42-400.avif" width="400" height="300" loading="lazy" decoding="async" alt="Leather boot">
</div>
css
.card-media { aspect-ratio: 4 / 3; background: var(--ph); }
.card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* trade-off: a flat colour conveys tone but not composition; it is the right
   default for grids where many images load quickly. */

2. Use LQIP selectively, as a CSS background

For a handful of large images (the hero, a feature image), a tiny blurred preview improves perceived quality. Put it on the container as a background so it cannot be an <img> LCP candidate.

css
.hero-media { aspect-ratio: 16 / 9; background: center / cover no-repeat url("data:image/webp;base64,UklGRj4AAABXRUJQVlA4…"); }
.hero-media img { opacity: 1; transition: opacity 200ms; }
/* trade-off: CSS background-image placeholders can themselves be LCP candidates
   if large and visible; a blurred low-content background is usually smaller in
   effective area or replaced quickly, but check LCP attribution after adding it. */

3. Decode BlurHash/ThumbHash at build time, not runtime

If your data source provides BlurHash strings, decode them to a tiny image or a few gradient stops on the server or at build time, and ship CSS — not a decoder.

javascript
// build step: turn a ThumbHash into a data URL once.
import { thumbHashToDataURL } from 'thumbhash';
const placeholder = thumbHashToDataURL(Buffer.from(product.thumbhash, 'base64'));
// trade-off: the data URL is larger than the hash string (a few hundred bytes),
// but it needs no client JavaScript and renders on first paint.

4. Fade in the real image without layout change

Swap or fade the real image over the placeholder within the same box; never change dimensions.

Which placeholder for this image? Decision sequence for choosing an image placeholder technique. Which placeholder for this image? One of many images in a grid or feed? Aspect ratio + dominant colour yes no Large hero or feature image where composition matters? LQIP as a CSS background yes no Data already includes BlurHash/ThumbHash? Decode at build time to CSS or tiny image yes no Aspect ratio + dominant colour

Verification

Check HTML size before and after, the absence of placeholder decoders in startup traces, LCP attribution (the final LCP should be the real image, not a preview), and CLS (zero shift on image arrival, verified with Layout Shift Regions).

Worked Example: A Real Estate Listings Page

A listings page rendered 60 cards with BlurHash placeholders decoded in the browser by a 7KB library onto 60 small canvases at startup. Startup scripting included 110ms of decoding on mid-tier phones, and some cards shifted when photos loaded because canvases had a fixed height while photos varied. The team replaced runtime decoding with build-time dominant colours, kept a single LQIP for the featured listing, and gave every card aspect-ratio: 3 / 2 with object-fit: cover. TBT fell by 120ms, CLS on the page dropped from 0.07 to 0.01, and users perceived the page as equally polished in a quick internal survey.

Placeholders and the LCP Metric

Placeholders interact with LCP in ways worth testing. An LQIP rendered as an <img> — or even as a large visible background — can be recorded as an LCP candidate when it paints. If the real image then paints in the same box, it produces a new LCP entry at its later time, and the final LCP is the real image, so the placeholder does not "fake" the metric. But if the user interacts before the real image paints, LCP stops at the placeholder, recording a misleadingly early value. For stable, honest measurement, keep placeholders as low-detail backgrounds on the container and make sure the real image is optimised as the true LCP element.

Common Mistakes

  • LQIP on every image. Inflates HTML for minimal perceived benefit in dense grids.
  • Runtime decoders at load. Main-thread cost when it matters most.
  • Placeholders as <img> LCP candidates. Confuses LCP measurement.
  • Mismatched aspect ratios. Layout shift when the real image arrives.

Edge Cases

Transparent images. Dominant-colour placeholders look wrong for logos and cut-outs on transparent backgrounds; use no placeholder or ThumbHash (which encodes alpha).

Dark mode. Light-toned placeholders flash on dark themes; derive placeholders from the image itself, not a fixed grey.

Image CDNs. Some CDNs generate dominant colours and tiny previews via URL parameters, removing build steps.

Low-bandwidth users. Placeholders are seen longer on slow networks; that is where LQIP's composition preview adds the most value.

FAQ

Do placeholders improve Core Web Vitals?

They improve CLS when they reserve space correctly. They do not improve LCP for the real image. Their main benefit is perceived performance.

Is BlurHash worth it over LQIP?

BlurHash strings are tiny in data payloads, which matters for APIs and mobile apps. For web pages, decoding them in the browser costs JavaScript; build-time conversion gives you the visual without the runtime cost.

How small should an LQIP be?

Around 16–40 pixels wide, heavily compressed (WebP or AVIF), typically 200–800 bytes, displayed blurred. Larger previews add bytes without much perceptual gain.

Should placeholders fade out?

A short opacity transition of the real image over the placeholder looks smooth and costs little (opacity is composited). Avoid animating size or blur radius, which repaint.

Do frameworks provide placeholders?

Yes — Next.js placeholder="blur", Nuxt Image placeholder, Astro and Gatsby image plugins. Check whether they inline data URIs per image and whether that HTML cost is acceptable for your page.

What about skeleton shimmers for images?

An animated shimmer is a placeholder too. Animate it with transforms, stop it under reduced motion, and keep it in a sized container; for images, a static dominant colour is often better.