メインコンテンツへスキップ
#SEO 約8分で読めます

Core Web Vitalsを自分のブログで改善したら、効いたのはほぼ画像とレイアウト確保だけだった

ブログのPageSpeed Insightsが50点台だった原因はほぼ画像だった。LCP・CLS・INPを静的ブログで改善した実体験から、効いた施策と効かなかった施策、小規模サイトでフィールドデータが出ない問題まで正直に書く。

このブログの前身サイトでPageSpeed Insightsを回したら、モバイルが50点台でLCPが真っ赤だった。当時の自分は「Core Web Vitals改善」で検索して出てくる網羅記事を上から順に試そうとして、クリティカルCSSのインライン化だの、JSのコード分割だのに手を出しかけた。

結論から言うと、そのほとんどは自分のサイトには関係なかった。効いたのは画像の圧縮と、レイアウトの事前確保。ほぼそれだけ。この記事は「全部やる」ガイドではなく、静的なブログで実際に何が効いて何が空振りだったかの記録として書く。

前提の整理:FIDはもう無い

手を動かす前に一つだけ。古い記事を参考にすると混乱するので書いておくと、Core Web Vitalsの3指標のうちFID(First Input Delay)は2024年3月にINP(Interaction to Next Paint)へ置き換わっている。今の3つはLCP(2.5秒以内で良好)、INP(200ms以内)、CLS(0.1以下)。

FIDが「最初の入力への反応」だけを見ていたのに対し、INPはページ滞在中の全インタラクションを対象にする。つまりごまかしが効かなくなった指標なのだが、後述するとおり、静的なブログでこれが問題になることはほぼない。

LCP:犯人は最初からわかっていた

Lighthouseの指摘の筆頭は「Properly size images」と「Serve images in next-gen formats」。スマホで撮った4MB級の写真を、リサイズもせずそのまま記事に貼っていたのだから当然だった。

やったことは3つ。幅1920pxへのリサイズ、WebP変換、品質80%。これだけで手元のアイキャッチは3.8MBから178KBになり、LCPはほぼ半分(4Gスロットリングで4.6秒→1.8秒)になった。この時の手順と品質設定の詳細は画像圧縮の記事に書いたので省くが、毎回の圧縮作業のためにブラウザ内で完結する圧縮ツールを自作して、以来アイキャッチは全部これを通してから載せている。

画像以外でLCPに効いたのは属性の付け方で、ここは一度失敗している。Lighthouseに言われるまま画像にloading="lazy"を一括で付けたら、アイキャッチまで遅延読み込みになってLCPが逆に悪化した。ファーストビューの画像はlazy厳禁で、むしろfetchpriority="high"を付けて優先させる。lazyを付けていいのはスクロールしないと見えない画像だけだ。

一方、網羅記事に必ず載っている「TTFBの改善」「CDN導入」「クリティカルCSSのインライン化」は、うちでは最初からやることがなかった。Astroでビルドした静的HTMLをCloudflare Pagesから配信している構成だと、サーバー応答は考えるまでもなく速い。SSGでホスティングがCDN配信なら、この章は丸ごと読み飛ばしていい。逆に言えば、WordPressなどサーバーが都度HTMLを組み立てる構成の人とは、やるべきことのリストが根本から違う。構成選びの話はSSGフレームワーク比較に書いた。

CLS:地味な作業が一番割に合う

CLSはレイアウトが読み込み中にずれる量。うちで原因になっていたのは2つだけだった。

一つはwidth/height属性のない画像。画像が読み込まれた瞬間に本文が下に押し下げられる、あれだ。全記事の<img>にサイズ属性を書いて回るだけで消えた。作業としては最高につまらないが、Core Web Vitals改善の中で一番コストパフォーマンスがいいのは間違いなくこれだと思う。

もう一つはWebフォント。フォント読み込み完了時に文字幅が変わって行折り返しがずれる。font-display: swapで表示自体は先行させられるが、swapの瞬間のずれは残る。size-adjustで代替フォントの幅を寄せる手もあるものの、調整がかなり面倒くさい。うちは最終的に本文を日本語フォントの自前配信ごとやめてシステムフォントに寄せた。日本語Webフォントはファイルが巨大でLCP側にも響くので、装飾を取るか速度を取るかの話で、自分は速度を取った。

あとは遅れて挿入される要素。広告枠やSNS埋め込みを使うなら、挿入先にmin-heightで先に領域を確保しておく。ずれてから直すのではなく、ずれる余地をなくす方向で考えるのがCLSの基本だった。

INP:静的ブログでは、ほぼ出番がなかった

正直に書くと、ブログ本体でINPが問題になったことは一度もない。クリックに反応が遅れるのはメインスレッドがJSで塞がっている時で、静的なブログにはそもそも塞ぐほどのJSがない。網羅記事にあるコード分割やrequestIdleCallbackの話は、SPAや管理画面のような重いアプリの技術で、ブログに持ち込んでも改善する対象が存在しない。

唯一意識したのはブラウザ内で重い処理をするページで、自作の画像圧縮ツールは大きい画像を複数枚まとめて処理するとcanvasの変換でメインスレッドを占有しがちだった。1枚ごとに処理を区切って制御を返すようにする、という古典的な対処で足りたが、「INPを気にするのはユーザー操作の直後に重い計算が走るページだけ」という感覚はここで掴んだ。

小規模サイトの落とし穴:フィールドデータが「無い」

一通り直してPageSpeed Insightsを開き直した時に知ったのだが、検索ランキングに使われるのはLighthouseのラボ計測値ではなく、実ユーザーの計測データ(CrUX)のほうだ。そしてCrUXには集計に足るトラフィックが必要で、立ち上げたばかりの小規模サイトだと「実際のユーザーのデータがありません」としか出ない。

つまりスコア90点を取っても、ランキング的にはまだ何も証明されていない。うちもしばらくこの状態だった。この段階でできるのはラボ計測で明らかな問題を潰しておくことと、Search ConsoleのCore Web Vitalsレポートにデータが溜まり始めたら実測ベースで見直すこと、くらいしかない。ラボの点数を1点単位で追い込むのは、フィールドデータが出てからでいい。

振り返ると、静的ブログのCore Web Vitalsは「画像を圧縮してサイズ属性を書き、ファーストビューだけ優先読み込みにする」でほぼ決着する。50点台から90点台に上がった要因の大半は画像だった。INPの最適化技術が必要になるのはもっとJSの重いサイトの話で、そこに時間を使うくらいなら記事を1本書いたほうがSEOには効く、というのが一周やった上での正直な結論だ。

#Core Web Vitals #LCP #CLS #INP #パフォーマンス
シェア