画像をドラッグするかクリックして選択
PNG, JPEG, WebP, GIF, BMP, AVIF
仕組み
プレースホルダーとは、画像がダウンロードされる間にその場所を占めるものです。役割は二つあります。画像が占める正確なスペースを確保して、表示された瞬間に周囲のテキストが動かないようにすること。そして最終的な内容に近いものを見せて、灰色の四角を眺めるよりも待ち時間を短く感じさせることです。
解決策は三系統あります。コンパクトなハッシュ(BlurHash と ThumbHash)は画像を非常に短い文字列に要約するので、レコードの他の項目と一緒にデータベースの列へ保存できます。ブラウザーがそれをデコードしてぼかしを描画します。データ URI(LQIP サムネイルと SVG)は符号化済みの画像を HTML や CSS の中に持つため、JavaScript は一切不要です。そして単色は最も安価なプレースホルダーで、わずか 7 文字です。
どれが向くかは HTML の生成元によります。画像がデータベース由来で数百件単位で一覧表示するなら、レコードあたりの軽さではハッシュが有利です。静的ページを生成する場合や、プレースホルダーに対応済みのフレームワークを使う場合は、データ URI ならデコード用のコードを足さずに済みます。ここに表示される値はすべてブラウザー内で計算されます。画像がサーバーへ送られることはありません。
例
blurhash 4 × 3LGHC162?|cKNqSWDjtaghVfjfQfjBlurHash の長さは成分数だけで決まり、画像のサイズや内容には左右されません。4 × 3 なら常に 28 文字、3 × 3 なら 22 文字、5 × 4 なら 44 文字です。thumbhash3wcKNZpwh3eAiIh3iHiIiHCAB/eHThumbHash は 17 〜 25 バイト、Base64 では 24 〜 36 文字です。正確なサイズは画像の縦横比と透過の有無によって決まります。この形式はアルファチャンネルも符号化するためです。lqip 24 px webpdata:image/webp;base64,UklGRi…幅 24 px の WebP サムネイルはたいてい 1 KB 未満に収まります。HTML に埋め込まれるため追加のリクエストは発生しませんが、別途キャッシュされない文書自体を重くします。ユースケース
- 画像テーブルに BlurHash や ThumbHash を保存し、一覧や無限スクロールのフィードで最初の瞬間から何かを表示する。
- 画像が静的インポートでない場合に、next/image の blurDataURL 属性や NgOptimizedImage の placeholder を埋める。
- プレースホルダーを width と height 属性と組み合わせ、商品カードや記事カードのレイアウトシフト(CLS)を防ぐ。
- デコード用の JavaScript を実行できない静的 HTML、メール、テンプレートにプレースホルダーを埋め込む。
- 同じ BlurHash を Web とモバイルアプリで使い回す。モバイルには Swift、Kotlin、Flutter のデコーダーがある。
- バイト予算がサムネイルすら許さない場合に、平均色をコンテナーの背景として使う。
よくある質問
BlurHash と ThumbHash のどちらを選ぶ?
ThumbHash はより少ないバイト数で画像を忠実に再現し、透過を保持し、アスペクト比も保存するため、描画に元のサイズを知る必要すらありません。BlurHash はより古く精度は劣りますが、はるかに多くのプラットフォームと言語に実装があります。ゼロから始めるなら ThumbHash、すでに BlurHash のデコーダーがスタックにあるなら移行する理由はありません。
これで LCP は改善する?
直接は改善しません。プレースホルダーは体感速度を高め、width と height と併せればレイアウトシフトをなくしますが、LCP は実際の画像の描画が完了した時点で計測されます。さらに言えば、主要画像が LCP 要素なら loading="lazy" を付けたりプレースホルダーの裏で遅延させたりしないでください。fetchpriority="high" を付けてブラウザーに早く要求させるほうが得策です。プレースホルダーはファーストビューの外にある画像のためのものです。
BlurHash の成分数はいくつが適切?
横長の画像には 4 × 3、縦長には 3 × 4 が向いています。成分を一つ増やすごとに 2 文字と少しの精細さが加わりますが、6 〜 7 を超えると肉眼では違いが分からなくなります。どのみち結果はぼかして表示されるからです。
ハッシュとデータ URI のどちら?
ハッシュは画像あたり数十バイトで、同じページに多数の画像がある場合に最適ですが、デコードするクライアント側のコードが要ります。データ URI は何も要りませんが、重さは 10 〜 50 倍で、しかも別途キャッシュされない HTML の中を運ばれます。目立つ画像が数枚ならデータ URI、長い一覧ならハッシュが向きます。
なぜサムネイルをそのまま使わず SVG を使うのか?
ぼかしを適用するのは SVG を描画するブラウザーだからです。おかげでずっと小さなサムネイルから始めても、拡大したときにピクセルのブロックが見えず、どんなサイズでも同じように滑らかに見えます。SVG はアルファを不透明に固定するので、ぼかしで縁が透けることもありません。
プレースホルダーにサイズの上限はある?
ツールによります。Angular の NgOptimizedImage は、プレースホルダーのデータ URI が 4000 文字を超えるとコンソールに警告を出します。そこから先は HTML の重さが利点を上回り始めるからです。これは一般的な目安としても有用で、サムネイルがこの値を超えるなら幅か品質を下げましょう。