Placeholder Blur

Low-quality blurred preview shown while an image loads.

Low-quality placeholder shown while the full image loads.

html

<figure class="ph-blur ph-blur--mint" style="filter:blur(14px);--ph-blur-ms:400ms;">
  <svg viewBox="0 0 320 200" width="100%" height="100%" role="img" aria-label="Placeholder preview while the full image loads"><rect width="320" height="200" fill="currentColor"/></svg>
</figure>

<p class="ph-blur__note">Low-quality placeholder shown while the full image loads.</p>

<!-- In production, remove the blur filter and swap in the full-resolution <img> on its "load" event. -->
<style>
.ph-blur { margin: 0; max-width: 320px; aspect-ratio: 8 / 5; border-radius: 10px; overflow: hidden; }
.ph-blur--mint { color: #A8E6C1; }
.ph-blur--sky { color: #BFD9F2; }
.ph-blur--blush { color: #F5C2E0; }
.ph-blur__note { margin: 8px 2px 0; font: 12px/1.4 system-ui, sans-serif; color: #24143099; max-width: 320px; }
@media (prefers-reduced-motion: no-preference) {
  .ph-blur { transition: filter var(--ph-blur-ms) ease; }
}
</style>

tailwind

<figure class="ph-blur-tw ph-blur-tw--mint m-0 max-w-[320px] rounded-[10px] overflow-hidden" style="aspect-ratio:8/5;filter:blur(14px);--ph-blur-ms:400ms;">
  <svg viewBox="0 0 320 200" width="100%" height="100%" role="img" aria-label="Placeholder preview while the full image loads"><rect width="320" height="200" fill="currentColor"/></svg>
</figure>

<p class="mt-2 mx-0.5 max-w-[320px] text-xs text-[#241430]/60">Low-quality placeholder shown while the full image loads.</p>

<!-- In production, remove the blur filter and swap in the full-resolution <img> on its "load" event. -->
<style>
.ph-blur-tw--mint { color: #A8E6C1; }
.ph-blur-tw--sky { color: #BFD9F2; }
.ph-blur-tw--blush { color: #F5C2E0; }
@media (prefers-reduced-motion: no-preference) {
  .ph-blur-tw { transition: filter var(--ph-blur-ms) ease; }
}
</style>

react

export function PlaceholderBlur({
  blurAmount = 14,
  theme = "mint",
  transitionMs = 400,
  caption = true,
}) {
  const swatch = { mint: "#A8E6C1", sky: "#BFD9F2", blush: "#F5C2E0" }[theme] ?? "#A8E6C1";
  return (
    <div>
      {/* In production, remove the blur filter and swap in the full-resolution <img> on its "load" event. */}
      <figure className="ph-blur-react" style={{ margin: 0, maxWidth: 320, aspectRatio: "8 / 5", borderRadius: 10, overflow: "hidden",
        color: swatch, filter: `blur(${blurAmount}px)`, "--ph-blur-ms": `${transitionMs}ms` }}>
        <svg viewBox="0 0 320 200" width="100%" height="100%" role="img" aria-label="Placeholder preview while the full image loads">
          <rect width="320" height="200" fill="currentColor" />
        </svg>
      </figure>
      <style>{`
        @media (prefers-reduced-motion: no-preference) {
          .ph-blur-react { transition: filter var(--ph-blur-ms) ease; }
        }
      `}</style>
      {caption && (
        <p style={{ margin: "8px 2px 0", font: "12px/1.4 system-ui, sans-serif", color: "#24143099", maxWidth: 320 }}>
          Low-quality placeholder shown while the full image loads.
        </p>
      )}
    </div>
  );
}