画像を91%減らしてもLighthouseは55点だった|犯人はWebフォント

画像を91%減らしてもLighthouseは55点だった|犯人はWebフォント

このブログの画像を全部WebPにして、転送量を91%削減しました。それだけやってから Lighthouse を回したら、モバイルのパフォーマンススコアは55点でした。

画像は犯人ではありませんでした。この記事は、実際に犯人を特定するまでに何を測って、どう切り分けたかの記録です。数字はすべて wadokon.com の実測値です。

目次

まず計測する|Lighthouseはコマンドで回せる

PageSpeed Insights のWeb版は手軽ですが、条件を変えて何度も比較するにはCLI版のほうが向いています。インストール不要で、これだけで動きます。

npx lighthouse "https://example.com/page/" \
  --only-categories=performance \
  --form-factor=mobile --screenEmulation.mobile \
  --output=json --output-path=./lh.json \
  --chrome-flags="--headless=new"

JSONで出しておくと、あとから好きな数字を取り出せます。スコアだけ見ていても改善点は分かりません。

現状の数字|遅いのは「読み込み」だけだった

指標実測良好の目安判定
パフォーマンススコア5590以上×
LCP(表示の速さ)18.3秒2.5秒以内×
FCP(最初の描画)16.3秒1.8秒以内×
CLS(レイアウトのずれ)0.000.1以下◎
TBT(操作の詰まり)0ミリ秒200ミリ秒以内◎
サーバー応答150ミリ秒600ミリ秒以内◎

この時点で切り分けが1つできています。CLSもTBTもサーバー応答も問題ない。悪いのは読み込みの部分だけです。JavaScriptの実行が重いわけでも、レイアウトがずれているわけでも、サーバーが遅いわけでもありません。

この切り分けを飛ばすと、「遅い」という感想に対してJavaScriptの分割や状態管理の見直しといった重い作業を始めてしまいます。3指標のどれが悪いかを先に確定させると、やらなくていい作業が大量に消えます。

転送量の内訳を見る|画像は4リクエスト23KBだった

種類リクエスト転送量割合
フォント951,092.8 KB58.1%
スクリプト16471.4 KB25.1%
スタイルシート10235.4 KB12.5%
HTML540.8 KB2.2%
画像423.1 KB1.2%
合計1371,880.3 KB

画像は全体の1.2%でした。WebP化をやり切った結果として、画像は完全に問題から外れています。

これは裏を返すと、画像最適化を先にやっていなければ、この表を見ても犯人が分からなかったということでもあります。大きいものから順に潰していくと、残ったものが自然に浮かび上がります。

そして、サイト自身のファイル(wadokon.com ドメインから配信されるもの)は25リクエスト・166.5KBだけです。1,880KBのうち1,713KBが外部ドメインからの読み込みでした。

無人のターミナルで、機械式の計量器に載せられたスーツケースを横から撮った写真
中身を減らしても、重さが変わらないことがある

犯人はWebフォント|日本語フォントは100分割で配信される

フォントの95リクエストという数字が異常です。中身を見ると理由が分かりました。

フォント用途ファイル数転送量
IBM Plex Sans JP本文64548.5 KB
M PLUS 1 Code見出し27505.8 KB
IBM Plex Mono日付など329.6 KB
テーマのアイコンフォントUI18.8 KB

日本語フォントは収録文字数が多く、1ファイルにすると数MBになります。そのためGoogle Fontsはunicode-range を使って100個前後のファイルに分割し、ページに出てくる文字が含まれるファイルだけを読ませる仕組みになっています。英語フォントが1〜2ファイルで済むのに対し、日本語は数十ファイルになるのはこのためです。

仕組みとしては合理的ですが、実際に読み込まれたのは日本語フォント2種類で1,054KBでした。特に見出しにしか使っていないフォントが505KBというのは、費用対効果として厳しい数字です。

加えて、フォント指定のCSSファイル自体も177KBあり、これが<head>で読み込まれるレンダリングブロッキングリソースになっています。このCSSを取得し終わるまでブラウザは描画を始められません。FCPが16.3秒という数字の主因はここでした。

止めて測る|仮説を数字で確かめる

「フォントが原因のはず」で終わらせず、実際に止めて測ります。Lighthouseには特定のURLをブロックして計測するオプションがあります。本番サイトを一切変更せずに「もし消したらどうなるか」を測れるので、改修の判断材料を作るのに便利です。

npx lighthouse "https://example.com/page/" \
  --only-categories=performance \
  --form-factor=mobile --screenEmulation.mobile \
  --blocked-url-patterns="*fonts.googleapis.com*" \
  --blocked-url-patterns="*fonts.gstatic.com*" \
  --chrome-flags="--headless=new"
そのまま55点・Webフォント停止63点・外部スクリプトも停止94点を比較した横棒グラフ
同じURLに対して、ブロックするリソースだけを変えて3回計測した結果
条件スコアFCPLCP転送量リクエスト
そのまま5516.3秒18.3秒1,880 KB137
Webフォントを止める634.7秒7.5秒619 KB41
フォント+外部スクリプトを止める942.0秒2.8秒177 KB29

Webフォントを止めるだけでLCPが18.3秒から7.5秒になりました。10.8秒がフォントの読み込み待ちだったことになります。

さらにアクセス解析タグと広告タグも止めると、スコア94・LCP2.8秒・転送量177KBになりました。サイト本体は十分に速い、という結論です。遅さは全部、外から読み込んでいるものが持ち込んでいました。

ここでスコアの動きに注目してください。フォントを止めた効果は55点から63点で、たった8点です。LCPが11秒近く縮んでいるのにこの程度しか動きません。スコアは複数指標の加重合計なので、点数の変化と体感の変化は一致しません。スコアを目標にすると判断を誤ります。見るべきは秒数です。

この数字の読み方には注意がいる

これはラボデータです。Lighthouseのモバイル計測は低速回線と低スペック端末をエミュレートするので、実際の利用者が18秒待っているという意味ではありません。条件を揃えた比較には使えますが、実ユーザーの体験を知るにはSearch Consoleなどのフィールドデータを見る必要があります。

それでも、同じ条件で3回測って出た差そのものは信用できます。絶対値ではなく差分を見るのがラボデータの正しい使い方です。

CLSが0だった理由

3条件すべてでCLSは0.00でした。これは運が良かったわけではなく、すべてのimg要素にwidthとheightが入っているためです。ブラウザはこの2つの値から縦横比を計算して、画像が届く前に表示領域を確保します。

これは画像最適化のときに確認していた項目でした。CLSは一度仕組みで潰しておけば、以後の記事でも自動的に0が維持されます。毎回気をつける対策ではなく、テンプレート側で構造的に防ぐ対策にしておくのが正解でした。

では何を削るのか|数字だけでは決められない

ここから先は技術の問題ではありません。フォントはサイトの見た目そのもので、外部スクリプトはアクセス解析や収益化という目的があって入れています。「1,700KB削れるから全部消す」とはいきません。

取れる選択肢を、効果とコストで並べるとこうなります。

  • 使っていないフォント読み込みを消す
    迷う理由がないので最優先。実際このサイトでは、テーマ側の設定で読み込まれた日本語フォントのCSSが、どこにも適用されないまま残っていました
  • 見出し用フォントをやめる
    505KB減る。ただし見出しの印象が変わる
  • 本文フォントをシステムフォントにする
    548KB減る。効果は最大だが、読み味が変わる
  • サブセット化してセルフホストする
    使う文字だけに絞れば劇的に軽くなる。ただしビルド工程が必要で、新しい文字を使ったときに欠ける事故が起きうる
  • 外部スクリプトを遅延読み込みにする
    描画を止めなくなる。計測の取りこぼしとのトレードオフ

計測の役割は、この判断を「なんとなく」から「505KBと引き換えに何を得るか」に変えることです。数字が出れば、消さないという判断も根拠のある判断になります。

まとめ|順番を間違えないこと

  1. 3指標のどれが悪いかを先に確定させる
    CLSとTBTが良好なら、JavaScriptの改修は不要と分かる
  2. 転送量を種類別に分解する
    思い込みで犯人を決めない。このサイトでは画像は1.2%だった
  3. 止めて測る
    本番を変更せずに効果を先に確かめられる
  4. スコアではなく秒数を見る
    11秒縮んでも点数は8点しか動かない
  5. 削る判断は数字を出してから
    技術的な最適解と、サイトとして守りたいものは別

画像を91%削減した作業は、スコアにはほとんど表れませんでした。それでも無駄ではなく、画像という大きなノイズが消えたおかげで本当の犯人が見えたという意味があります。最適化は、大きいものから順に消していく作業でもあります。

次に読む記事

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

わどこんのアバター わどこん

実務12年のバックエンド・インフラエンジニア。バックエンド開発からクラウド・インフラの設計・構築・運用まで担当しています。主要言語は Java・Kotlin・PHP・Python。運用の現場で拾った知見を、再現できる手順に落として残すのがこのブログのテーマです。

目次