やあ。今日もブラウザのメインスレッドと格闘しているかい?
フロントエンドの世界に入ってしばらくすると、誰もが一度は「なぜか画面がカクつく」「LCP(Largest Contentful Paint)が改善しない」という壁にぶつかる。その犯人の多くは、実はHTMLのパース中に突如として現れる「巨大な画像」だったりするんだ。
今日は、ブラウザのレンダリングパイプラインの深淵、特に画像デコードの裏側について、現場の知見を交えて話そうと思う。ここを理解しているかどうかで、君の書くコードの「滑らかさ」が劇的に変わるはずだ。
—
ブラウザは「画像」という重荷をどう処理しているのか
まず、ブラウザが画像を表示するまでのプロセスを思い出してほしい。
HTMLがパースされ、DOMとCSSOMが構築され、Render Treeができる。その過程でブラウザは画像タグを見つけると、ネットワークからバイナリを取得する。しかし、ネットワークからデータが届いただけでは、画面には表示できない。
なぜなら、ブラウザは画像を表示するために、圧縮されたバイナリデータを「ピクセルデータ(ビットマップ)」に変換する必要があるからだ。これがデコード(展開処理)だ。
問題はここにある。このデコード処理は、デフォルトではメインスレッドで行われることが多い。巨大なJPEGやPNGを、レンダリングの真っ最中にメインスレッドでデコードしようものなら、ブラウザは「ちょっと待ってくれ!」とばかりにフリーズし、ユーザーはカクつきを感じるわけだ。
—
現場で使える「デコード最適化」の切り札
この問題を解決するために、僕らが打てる手は主に2つある。
1. `HTMLImageElement.decode()` で「空気を読んで」デコードする
もし君が、JavaScriptを使って動的に画像を追加するSPAのようなアプリを作っているなら、このメソッドは必携だ。
通常、`new Image()` でソースをセットしてDOMに追加すると、ブラウザは「今すぐ表示せねば!」と焦ってデコードを始める。これを防ぐために、DOMに追加する「前」に、非同期でデコードを済ませてしまうんだ。
/
- 画像をスムーズに挿入するためのユーティリティ
- @param {string} src – 画像のソースURL
/
async function loadAndAppendImage(src) {
const img = new Image();
img.src = src;
try {
// 1. デコードが完了するのを待機(非同期処理)
// これにより、メインスレッドをブロックせずに準備ができる
await img.decode();
// 2. デコード完了後にDOMへ挿入
// この時点で画像は既にメモリ上でピクセル化されているので、
// 画面に現れた瞬間に「ヌルッ」と表示される
document.body.appendChild(img);
console.log(‘画像デコード完了、描画準備OK’);
} catch (error) {
console.error(‘画像のデコードに失敗しました’, error);
}
}
このコードの肝は、`await img.decode()` だ。これを通すことで、ブラウザは「デコードが終わってからDOMに追加される」ことを確約できる。これにより、描画時のレイアウトシフトや、カクつきを劇的に抑えることができるんだ。
—
2. `loading=”lazy”` との賢い付き合い方
次に、HTMLで静的に書く場合の最適解についても触れておこう。
最近は `` を使うのが定石だが、一つ注意点がある。「LCP候補になる画像にlazyを付けてはいけない」ということだ。
- ヒーロー画像(ファーストビュー): `loading=”eager”`(デフォルト)+ `fetchpriority=”high”` を指定。
- それ以外の画像: `loading=”lazy”` でパースの優先順位を下げる。
さらに踏み込むなら、`fetchpriority` を組み合わせるのが現代のWebパフォーマンスチューニングの鉄板だ。

![]()
—
なぜこの仕組みを知る必要があるのか
君がもし「なんとなくコードを動かしている」状態から脱却したいなら、ブラウザが「いつ・どこで・何を」計算しているのかを常に意識することだ。
画像デコードの最適化は、単なる「速さ」のためじゃない。ユーザー体験(UX)の質を担保するためだ。 どんなに良いデザインでも、スクロールのたびに画面が引っかかるようなサイトは、ユーザーにとって「壊れている」のと同義なんだよ。
今日のこのTipsは、明日からの現場ですぐに使える。まずはプロダクトのLCP要素を確認し、`decode()` や `fetchpriority` を適切に配置できているか見直してみてほしい。
何かあればいつでも聞いてくれ。エンジニアリングの深淵は、まだまだ深いからね。

コメント