タイトル通り PageSpeed Insights で 4 項目オール 100 点を取って、 FCP と LCP をモバイルとデスクトップ両方で 1 秒未満にした話です。 2026 年 4 月〜 7 月にかけての備忘録です。
目次
施策前後の PageSpeed Insights
| 施策前 | 施策後 | |
|---|---|---|
| パフォーマンス | 67 | 100 |
| ユーザー補助 | 77 | 100 |
| おすすめの方法 | 100 | 100 |
| SEO | 85 | 100 |
| First Contentful Paint | 2.2 s | 1.0 s |
| Largest Contentful Paint | 6.4 s | 1.0 s |
| Total Blocking Time | 140 ms | 20 ms |
| Cumulative Layout Shift | 0 | 0 |
| Speed Index | 6.7 s | 1.0 s |
あまりにも PageSpeed Insights の点数が悪かったので、デザインはまったく変えず、改善を加えること 2 か月半、 PageSpeed Insights にてオール 100 点となり、その後も改善を加えて FCP と LCP がモバイルとデスクトップ両方で 1 秒未満となったので、その経過を備忘録として残しておきます。
改善を試みようと思ったきっかけ
大きなサイズのディスプレイでこのサイトを見るとフロントページの最新記事のサムネイルにグレーの枠がついていたのを修正したました。ガラケー対応のプラグインなど不要になったものを停止しました。
そして久しぶりに PageSpeed Insights をかけてみたらなんとも散々な結果でした。 2019 年の 8 月に計測したときは 98 点だったのに。
調べたところ LCP (Largest Contentful Paint) という指標が 2020 年 5 月に Google から発表され、 2021 年 6 月中旬から本格的に検索ランキング要因の一部として取り入れられているようです。パフォーマンスの点数が伸びないのは LCP が 6.4 秒と壊滅的に遅いのが原因です。
施策の方向性と実際の施策
FCP (First Contentful Paint) → LCP (Largest Contentful Paint) → L (Load) の順で速くなるようにしました。 PageSpeed Insights はエンジンが Chromium なので、 Chrome メインで調整しながら、適宜 Safari や Firefox でも確認しました。 IE はサポートから外しました。 Microsoft Edge は Chromium ベースに変わったので、 Chrome で大丈夫なら確認しなくてもいいはずです。
FCP を速くする
FCP を速くするためにはファーストビューのスタイルシートをインラインに埋め込みます。わたしのデザインだとそれだけだとなぜか強制リフローが起きるので、その下の初めの p タグだけファーストビューに含めました。
クリックしないと見えないメニューの中身は親要素に visibility: hidden; と pointer-events: none; を設定し、 :checked のタイミングで visibility: visible; pointer-events: auto; にしました。
そして #nav-content の中身は外部 CSS に記述します。その外部 CSS はプリロードでロードし終わったタイミングで link 要素に変更したします。
JavaScript は </body> 直前に置いています。(最終的には一部を除き遅延読み込みにしました)。
LCP を速くする
このサイトはファーストビューに背景画像に載った h1 タグとメニューしかほぼないので、 LCP を速くするためには、 h1 タグが載っている画像の読み込み、および表示を速くすることが必要です。
背景画像の最適化
具体的な対策は Google フォトの URL を使うのをやめ、自分のサーバーに画像を WebP 形式で置き、 CSS でぼかしを入れているので画像の画質も最低にして、画面の半分の高さにして容量を小さくしたものを読み込むことにしました。これで 500 ms 程度削れました。
画像の読み込みに関しては以下の記事に改善の模索を書いています。
また h1 の背景となる画像は予めプリロードしておくのが大事です。
background-image から img タグに変更
背景画像だとページの DOM 構築が終わってから表示されるようで、プリロードしていてもどうしても FCP と LCP が遅くなります。なので img タグを直接 body 配下におき、 position: fixed; z-index: -2; で背景固定して裏に回しています。その前にカラーのついたはレイヤーを一枚置き透過で写真の色を変えています。
img タグに decoding="async" loading="eager" fetchpriority="high" を設定すれば、最優先で読み込みを初めてくれるのですが、さらにプリロードをつけた方が読み込み開始が 20 ms ほど早くなります。
Firefox の DPR 2 以上のディスプレイで画像が 2 枚ダウンロードされるバグ
preload に media をつけてブラウザの高さに合わせて読み込む画像を指定しているのですが、 Firefox の DPR が 2 以上( Retina ディスプレイ)の場合はなぜか preload の画像がうまく判別されないようで、 2 つ画像が読み込まれてしまいます。
このサイトは約 63 % がモバイルからの接続で、 35 % ほどがデスクトップです。デスクトップでの Firefox のシェアは以下のサイトによると 5.8 % で、デスクトップにおけるマックのシェアは 11.94 % です。
→ 王道 DX :【 2025 年 10 月調査】日本・世界の Web ブラウザシェア率のランキングと推移
→ Arc Communications :世界と日本の OS シェアを調査!【 2025 年 9 月】
計算してみると以下のようになりす。
0.35 × 0.058 × 0.119 = 0.00242
デスクトップかつ Firefox かつ Mac のユーザーは計算では 0.24 % です。そのうち Retina ディスプレイで Firefox を使っている人はさらにら少なくなります。全体の 0.1 % もいないのではないかと推測されます。具体的なユーザーを思い浮かべると、 MacBook Pro 等で Firefox ユーザーということになります。 Firefox の Retina 時の画像の二重読み込みは目をつぶることにしました。
その他の改善点
また Goolge フォトに画像を置いていたときは画面の応答速度が遅かったので誤魔化すためにフェードインのアニメーションを入れていたのですが、アニメーションがちゃんと表示されるまでの時間も計測の対象になるようです。そこで自分のサーバーに画像データを置くことで画像の表示が速くなったので、ファーストビューのアニメーションは最終的に廃止しました。
それでも LCP が 2.5 秒とギリギリ合格範囲なので、根本的な見直しが必要と感じ、デザインは変えず Flexbox でレイアウトしてたのを Grid レイアウトに全面改修しました。苦労したかいあって 300 ms ほど速くなりました。
アイコンの Web フォントを使っていたのですが、読み込んで背景で設定するとどうしても遅くなるので、ファーストビューの部分だけ svg 埋め込みにしました。
content-visibility: auto; をインラインにまとめて設定していたのですが、外部 CSS にしたほうがよいようなので変更しました。
L を速くする
これは </body> 直前に回した JavaScript や CSS 、 Web フォントをさらに遅延読み込みで、 Load やスクロールなどのイベントで読み込みし実行させるようにしました。 Google Analytics だけは Load 後すぐ読み込むようにし、あとは Load 後 3 秒後やスクロールやクリックがあった場合に読み込むようにしました。画像を拡大表示する PhotoSwipe は CSS も読み込むのでそれも遅延読み込みしました。あとはコードを表示している Prism の JavaScript と CSS も遅延読み込みにしました。
しかし Google Analytics は Load イベントで遅延読み込みにすると、そこから外部スクリプトを読み込み実行するのでデータが送信されるのが遅くなります。そこであえて preload で先読みさせ、実行だけ Load にしました。これで大体約 620 ms 後にスクリプトの評価が走り、実際にデータが送信されるのが、 700 ms くらいです。これくらいの遅延ならば問題ないでしょう。
初めはスクリプトひとつひとつにインラインで読み込みタイミングを設定いていたのですが、あまりにコードが汚いし管理も大変なので、 Gemini に手伝ってもらって自作の遅延読み込みの JavaScript を作りました。初期設定を配列に入れるようにして、その配列を WordPress 側で自動で生成しています。
fetchpriority=”low” を設定していても下部の画像が先に読み込まれる
fetchpriority="low" を設定していてもページの下の方にある画像がなぜが最初の方に読み込まれていました。これも原因がわからず、 Gemini に聞いてみたら、高さをがわからない場合画像を読み込んでしまうようです。通常は img タグに width と height が設定されていたらそのようなことは起きないのですが、一部 srcset でアスペクト比の違う画像を読み込ませているのが原因のようです。そこで css のメディアクエリにて aspect-ratio を設定してやったら、下部の画像の読み込みがなくなりました。
強制リフローを潰す
これが一番手強くて本当に苦労しました。テストしたページには AdSense と X (Twitter) の埋め込みがあり、これらを遅延読み込みにしていても足を引っ張りスタイルの再計算が起こるのです。
body 直下の要素に contain: layout style; を設定しました。これでその要素が独立して他のレンダリングが変わってもスタイルの再計算をしないから、強制リフローを防げます。
頑固でどうやっても目次と埋め込み部分に強制リフローが起こるので、以下のようにして対応しました。これで要素が増えても縦長になります。
AdSense はモバイルとデスクトップで配信される広告のサイズが変わるので、以下のように枠を作りサイズはメディアクエリで設定しました。
contain: strict; だと高さが固定されてしまうので、このような指定になっています。
強制リフローがなくなりすっきりしました。
使用していない JavaScript の削減に /gtag/js が表示されますが、これは Load 後に使っているから気にしないことにしました。 LCP の速さ早ければ、改善が必要の黄色が出ていても、パフォーマンスで 100 点は取れます。ない方が 100 点が出やすいですけれど。
CSS を圧縮したら 150 ms 遅くなる
テスト環境でそのままの CSS をインラインにしているときは大丈夫だったのに、圧縮してインラインに入れたら、レイアウトの再計算が置き FCP と LCP が 150 ms ほど遅くなりました。これはパケットの切れ目と、今は使っていない擬似要素が残っていたことによるタイミングの問題でした。擬似要素を削除したら問題はなくなりました。
パケットの問題でスタイルの再計算が起きる
Chrome の開発環境のパフォーマンスにて、背景画像を読み込んだ後待機しているので、プリロードはいらないのではないか、と廃止したら、今度は再レンダリングが起きるようになってしまいました。どうやらパケットの切れ目が埋め込みの svg のデータの途中になるらしくレンダリングをやり直しているようです。ということで背景画像のプリロードに戻すと再レンダリングはなくなりました。
サイトの改修記録
実際の作業内容を時系列順に書き出しました。完全なる備忘録です。
サイトのメンテナンス
- フロントページの最新記事のサムネが大画面だと小さく表示される不具合修正
- 画像の遅延読み込みを Lazysizes からブラウザ依存の
loading="lazy"に変更 - モバイル画面の大画面化により
srcsetの画像のサイズを変更 - 2026 年 3 月末日でガラケーが全てのキャリアで停波したので Ktai Style を停止
- Photo Express for Google 削除して表示部分のみ新規にプラグインを作成
- PhotoSwipe を v5 に変更し、上記の自作プラグインに統合
- ファーストビューの画像はぼかしを入れているので 1/2 のサイズを読み込むようにした
PageSpeed Insights の要改善点を潰す
- 本文の画像を WebP 形式にする
- ファーストビューの画像をキャッシュ日時を長くする
- フロントページサムネイルの
srcsetを細かくし基準を縦に変更 - テキストのコントラスト改善
aタグの範囲が狭かったものがあったので 24 px 以上に改善asideタグ内h6タグをpタグに変更(構造でエラーになる)- X (Twitter) 埋め込み機能で読み込まれる JavaScript を遅延読み込み
- カエレバの正規表現修正
- アフィリエイトの画像に
altとwidthとheightを正規表現で追加 - サムネイルの画像も WebP に変更
pictureタグとsourceタグを使って WebP に非対応のブラウザでも JPEG 画像が表示されるようにした(なぜか点数が下がった)
ファーストビューの画像を自分のサーバーに置く
- Google フォトの画像の待機時間が長いのでので、ファーストビューの背景画像だけ自分のサーバーに置いた
- 特に Blogger 経由で URL を取得した写真は応答時間が 500 ms 以上と長いのでファーストビューの背景画像だけ低品位の WebP 画像にして自分のサーバーにおくことにした
- 画像のサイズ書き出しには GIMP の Batcher にてバッチ処理した
- ぼかしているので画質クオリティを最低まで下げたが低品位では AVIF より WebP の方が容量が少なかったので WebP を採用
content-visibility: auto; の設定と JavaScript の遅延読み込みタイミングの見直し
- PhotoSwipe のライブラリの読み込みが遅いので
link要素で先読みするようにした - ファーストビューのメニューなどの非表示部分をレンダリングしないように、 CSS で
content-visibility: auto;を設定 - 投稿が表示されないページがあるのは正規表現で配列に入れている部分がメモリを食うようなので
unsetする(これはのちにコメントアウトした際に正規表現に?>という文字列がありファイルの終わりと認識されていたとわかった) - コードを表示する Prism.js のバージョン 5 に上げ、テキストの折り返しに対応させる
- Google Analytics を GTM の配信に変更し、トリガーを「ウインドウの読み込み」 (Load) に変更
#post-content、footer、#post-footerにcontent-visibility: auto;を設定しレンダリングを後回しにしcontain-intrinsic-sizeも設定appear-header.jsの強制リフローを排除- Web フォントを CSS にて
contentで挿入しているところを予め幅と高さを確保
- Google Tag Manager にしたら点数がよくなったと思ったら、「公開」ボタンを押してなくて、 Google Analytics のコードが読み込まれていないだけだった
- JavaScript の遅延読み込みの発火点の見直し
DOM の最適化のため Grid レイアウトに変更と自動挿入されるスタイルシートを削除
- LCP が 2.5 s とギリギリ合格ラインなので、もっと速くするため DOM の数を減らす方向で Grid レイアウトにし HTML と CSS をほぼ全面改修
- アニメーションの見直し、カラーを乗せたオーバーレイをフェードアウトするのではなく、さらに疑似要素を追加しその要素をフェードアウトさせた(ブラウザのレンダリングエンジンは「背景の色と画像は最初から完成している」とみなし、結果として、 LCP の計測ロジックがアニメーションに邪魔されず、最速のタイミングで確定する)
- クラシックブロックスタイルとグローバルブロックスタイルの両方を削除(
classic-theme-stylesとglobal-styles)
→ SOFTEL メモ Developer’s blog :[WordPress] classic-theme-styles-inline-css の削除
→ ONZE/BLOG :【 WordPress 5.9 】緊急対応「 global-styles-inline-css 」を削除する方法
- REST API のリンクタグをヘッダーから削除
- 外部ツールからブログ記事を投稿する機能( XML-RPC )を削除
- PageSpeed Insights とローカルの Chrome の Largest Contentful Paint の値の差が大きすぎる。計測サーバーがアメリカだから日本からアメリカまでの経路が混んでいたらよい数値が出ないようだ。午後 14 時から午後 15 時半くらいまで(アメリカが深夜かつ日本のトラフィックが低め)、と午前 5 時頃(日本のトラフィックが低め)が高得点が出やすい。(後にもっと最適化したらコンスタントに高得点が出るようになった。)
- 自作テーマを見直し Grid レイアウトを採用し HTML とスタイルシートを書き直したら、 DOM の深さは減ったが合計要素数は増えたが 300 ms ほど速くなった。
| 施策前 | 施策後 | |
|---|---|---|
| 合計要素数 | 853 | 858 |
| DOM の深さ | 15 | 12 |
| 子の最大数 | 66 | 66 |
再レンダリングを潰す
- 再レンダリングが発生しているので、プリロードしているので Web フォルダの
&display=swapを外すが再レンダリングされる - ファーストビューにある Web フォントを svg 埋め込みにし
</body>直前でプリロード - 以下のコードだとページロードイベントが発火しない→ URL に不要なスペースが入っていた
- 以下のコードにするとページロードイベントが発火する
- Google Analytics を GTM から直書きの JavaScript に戻す。発火は Load にしたら GoogleAnalytics の実行が、 2000 ms から 1800 ms 程度になる
- すぐに使わない JavaScript をスクロール後 200 ms で読み込むように変更
- Load イベントが 1000 ms で発火し GoogleAnalytics の実行が速くなった
- Google Analytics は
https://analytics.google.com/g/collect?v=2が読まれたタイミングで計測が送信される。 Analytics だけ load 後に読み込んでも AdSense がある場合、https://analytics.google.com/g/collect?v=2が読み込まれるのは AdSense が読まれた後なので、 Analytics と AdSense を同じタイミング load イベントで読み込むようにする。変更しても LCP 、 L の秒数は変わらない。
デザインを変えていないのにユーザー補助で警告が出る
- デザインをまったく変えていないにも関わらず、「ユーザー補助」の項目に「背景色と前景色には十分なコントラスト比がありません」と「タップ ターゲットのサイズや間隔は十分な大きさではありません。」の警告が出た。 Gemini に聞いたりして実践しても全然改善されなかったが、
contain-intrinsic-sizeを80pxから300pxにしたらエラーなしで 100 点になった。
詳しくは下記の記事に書いてある。
このあたりから PageSpeed Insights でオール 100 点が出るようになる。なので調整には Chrome の開発環境のパフォーマンスを主に使った。
遅延読み込みを一括管理する JavaScript を作成
- JavaScript を個別にインラインで遅延読み込みしていたが、まとめて遅延読み込みを管理できるように、 Gemini に聞きながら WordPress 側で初期設定の配列を作成し元のコードを削除し、それを元に遅延読み込みする JavaScript を作成した
- YouTube の埋め込みが記事の上の方にあると
loading="lazy"でも load イベントが遅くなり Google Analytics を load のタイミングで実行しているので致命的。これは WP YouTube Lyte というプラグインを入れて対応した。 load が 3.52 s から 1.03 s に短くなった。計測は下記ページで行った。
JavaScript や CSS 、 Web フォントの読み込み順の見直し
Chrome の Lighthouse でチェックして、問題ある部分を修正。プリコネクトに gtm も入れてロード後の読み込み開始を速くした。最終版としたかったが、 LCP が 800 ms 台と遅くなる。
コードの読込み順を見直す。ヘッダーの消えたり現れたりする JavaScript をインラインに埋め込んでいたが、どうやらレイアウトシフトを起こしているようなので、ファイルにしてスクロール後に読み込むように変更。遅延読み込みの JavaScript をファイルにしプリロードさせた。 Google Analytics の GTM の JavaScript をプリロードするようにした。 Load 後すぐに実行されるので、計測の遅延が少なくなった。アイコン等をまとめている Web フォントは head でプリロードするとなぜか LCP が遅くなるので、 </body> 直前でプリロードさせた。 CSS に書くのだと DCL のタイミングで読み込むのでそれより少しだけ速くなり Load イベントが早く発火するようになった。モバイル( CPU : 4 倍減速、ネットワーク:高速 4G )にて LCP 700 ms 台、 Load が 1000 ms 台。
ファーストビューの Web フォントはすべて svg の埋め込みにしたので、 Web フォント自体をページロード後に読み込めばいいのではないのかと思い、自作の JavaScript に Web フォントの遅延読み込みの機能も追加した。しかし Lighthouse で「ネットワークの依存関係ツリー」の警告が出てしまった。そこでロード後 3 秒後に読み込むように変更した。( 2 秒後だとまだ警告が出たため。) LCP 800 ms 台前半、 L も 900 ms 台となった。
YouTube の埋め込みがあるページが遅いので、 WP YouTube Lyte というプラグインで最初は埋め込みをサムネイル画像のみにする。なぜかモバイルだと画像にならないので、以下のフィルターを function.php の適当なところに設定した。
Safari にて遅延読み込みした Web フォントが認識されないのを修正
本番環境のみ Safari で Web フォントが□に✕が重なった文字になる。以下をつけ加えたらきちんと表示されるようになった。
Safari の開発環境のネットワークで確認すると、フォントファイルの .woff2 を js として認識しているのが問題なようだ。
Css の Web フォントの箇所に以下追加
サーバーの .htaccess に以下を追加
Safari でキャッシュを削除して再読み込みして woff2 として認識されているのを確認。 iPhone はプライベートウィンドウを開いて正常に表示されているのを確認した。(普通のウィンドウだとキャッシュが切れるまでダメみたいだ。パラメーターを変更すればいいのかも。)
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 513.43 ms | 171.85 ms |
| LCP | 513.43 ms | 171.85 ms |
| DCL | 573.89 ms | 136.39 ms |
| L | 644.08 ms | 147.03 ms |
Chrome のディベロッパーツールのパフォーマンスにて、サイズ Pixel 7 CPU 4 倍減速 ネットワーク 高速 4G を基準にしていたから、気がつかなかったけれど、 CPU とネットワークの制限なしにしたら、 FCP と LCP が L より遅いという逆転現象が発生した。この原因はファーストビューにつけているアニメーションのせいだと思って削除した。
アニメーションを削除したら、他の要素を読込み初めて LCP が 875.54 ms とかえって遅くなる。
フッターの方にある画像をなぜか読み込むので Gemini に聞いたら、アスペクト比がわからないと画像を読み込んでしまうようで、 width と height をしっかり指定し、画面サイズで変わる部分は CSS でアスペクト比を設定した。あと高さがわからないと先にレンダリングしてしまうらしいので、高さも CSS で指定した。
JavaScript を全部オフにしても強制リフローが起こるので、 CSS を修正した。ファーストビューにもあるのを忘れていて、読み込みの CSS でクラス名を使ってまとめて指定しまっている部分があり、スタイルシートの書き換えた起こっていた。 :not() で除外したら強制リフローは起こらなくなった。
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 888.41 ms | 589.95 ms |
| LCP | 888.41 ms | 589.95 ms |
| DCL | 1.43 s | 539.26 ms |
| L | 1.47 s | 623.29 ms |
埋め込みの SVG に width="100%" height="100%" と指定していたため、一度画面いっぱいに SVG をレンダリングしたあと、 CSS のサイズにレンダリングし直していたようだ。 width="20" height="20" と実際のサイズにしたら、 SVG のよる再レンダリングはなくなった。
強制リフロー解消
自作の遅延読み込みの JavaScript をインラインに戻した。
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 866.20 ms | 620.17 ms |
| LCP | 866.20 ms | 620.17 ms |
| DCL | 1.54 s | 571.47 ms |
| L | 1.59 s | 610.79 ms |
HTML のソースを見直していたら見慣れないインラインスタイルが挿入されいた。
これは WordPress 6.7 から挿入されるようになったようです。このせいで強制リフローがおきていたので削除した。
遅延読み込みの JavaScript をファイルでプリロードで読み込むのに戻しました。 LCP は 20 ms ほど遅くなるが、 Load イベントが発生するのが早くなるため、 Load で発火する Google アナリティクスの精度が上がる。
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 846.32 ms | 619.26 ms |
| LCP | 846.32 ms | 619.26 ms |
| DCL | 1.53 s | 580.43 ms |
| L | 1.58 s | 592.47 ms |
日曜早朝は回線状況がよくサーバーの応答時間も短いので速くなる。
Google のタグマネージャーの読み込み Load イベントより遅くボトルネックになっている。
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 764.49 ms | 597.01 ms |
| LCP | 764.49 ms | 597.01 ms |
| DCL | 1.07 s | 561.18 ms |
| L | 1.11 s | 573.92 ms |
強制リフローとレイアウトの再計算を潰す
- ファーストビューのインライン CSS にて
footerを用いて指定したら、強くなっていたので、セレクタの強さを調整して解消 - 画像の親要素に
contain: layout;を追加 - インラインに入れるべき CSS のプロパティを根本的に誤っていた。 Gemini によるとファーストビューはすべていれるが、それ以外も骨格となるべき部分(装飾以外)はすべて入れると強制リフローが起こりにくくなるようだ。(これは外部 CSS と遅延 CSS のことで間違っているのでマネしないで!)
- JavaScript の遅延読み込みのタイミングを 各 JavaScript ごとに setTimeout を使って少しずつずらし、 31ms を 32 μ s に改善
- 目次の遅延スクロールの JavaScript をタイマーと非同期化
- PhotoSwipe の
:has()を他のセレクタに変更 - FCP 前にレイアウトの再計算が置きていたのは、
</li>前の改行とタブが入っていた構文エラーのためだったので修正 content-visibility: auto;を設定する要素を間違えておりレイアウトの再計算が発生していたため適切に設定し再計算をなくす- ページロード完了時に Twitter の iframe の置き換え、
contain: layout style;で壁を作って回りに影響を与えないようにする - 遅延ロードの画像のフェードインを
IntersectionObserverにより完全分散
目次部分との Twitter ( X )埋め込みの強制リフローをcontent-visibility: auto;とcontain: layout style;でなくす .post-contentにcontent-visibility: auto; contain-intrinsic-size: auto 2000px; contain: layout style !important;を設定することで、親要素のサイズ計算のブレに巻き込ませないcontent-visibility: auto;を設定した場合子要素にcontent-visibility: visible;してもvisibleは効かない。- 強制リフローが発生していたので、
body直下の要素にcontain: layout style;を設定。これでその要素が独立して他のレンダリングが変わってもスタイルの再計算をしないから、強制リフローを防げる。 - AdSense は JavaScript でインラインに CSS を
!importantつきで挿入してくるので以下で対応(contain: strict;だと高さが固定されてしまう)
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 674.46 ms | 572.37 ms |
| LCP | 674.46 ms | 572.37 ms |
| DCL | 1.14 s | 529.58 ms |
| L | 1.21 s | 561.87 ms |
FCP 0.9 s 、 LCP 1 s 、 TBT 70 ms 、 CLS 0 、 Speed Index 1.6 s
- インラインに骨格に関するプロパティを入れたけれど、そのページに関係のないスタイルシートも含まれていることに気がつき、ファーストビューのスタイルシートを分割し、投稿ページ、個別ページ、フロントページ、その他で読み込ませるスタイルシートを変えることにした(変更前 39.6 KB → 37.3 KB )
- クリティカル CSS (ファーストビューの CSS )と外部 CSS と遅延 CSS の 3 つがあることに気がついていなくて、外部 CSS と遅延 CSS の分け方をインラインと外部 CSS に当てはめていたので修正。ただし
content-visibility: auto;を設定した部分はcontent-visibility以外は通常の CSS に移した。 - モバイルの開閉するメニューを
visibility: visible;を設定し、中身は外部 CSS に移す - 背景画像の
imgタグにwidthとheightの記述がなかったので追加 - スタイルの再計算をしているので、ファーストビューレンダリング時にスクロールバーが表示されないので、
scrollbar-gutter: stable;で予め確保で 114.80 ms が 3.45 ms に短縮 - CSS 圧縮したらレンダリングの再計算が起きて 150 ms ほど遅くなった。ファーストビュー以外の部分もレイアウトし始めてしまうので、外部 CSS の実行タイミングを DCL にした。これでテスト環境で 600 ms 台後半になった
- その後昔の残骸の
::afterの擬似要素が残っているのを見つけて削除 - 1 回目の送信でファーストビューの CSS を送り切るのが大事。それ以上になるとスタイルの再計算になってしまって遅くなる。
- がんばって最適化してもデスクトップで 500 ms 台、モバイルで 800 ms 台くらいで強制リフローが起きていた頃の方が速かった。
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 783.43 ms | 586.23 ms |
| LCP | 783.43 ms | 586.23 ms |
| DCL | 823.64 ms | 552.62 ms |
| L | 930.32 ms | 563.10 ms |
content-visibility: auto;をまとめてインラインに書いていたのを外部 CSS に移動- 画像の読み込み後待機しているので、画像のプリロードを廃止
- 背景画像のプリロードなしにするとスタイルの再計算が起こる
- 日曜早朝に計測(画像のプリロードをなし)したら、モバイルのみ SVG の埋め込みあたりでスタイルの再計算が起こる
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 399.81 ms | 257.09 ms |
| LCP | 583.14 ms | 257.09 ms |
| DCL | 1.41 s | 203.64 ms |
| L | 1.44 s | 803.80 ms |
- 同じく日曜早朝に測定して画像のプリロードすると強制リフローが起きない。パケットの切れ目が埋め込み SVG に当たらないため。プリロードなしの場合パケットの切れ目で画像をダウンロードしようとするため強制リフローを起こすようだ。
| モバイル | デスクトップ | |
|---|---|---|
| 環境 | サイズ: Pixel 7 CPU : 4 倍減速 ネットワーク:高速 4G |
サイズ: 1440 × 113 CPU :なし ネットワーク:なし |
| FCP | 592.36 ms | 181.63 ms |
| LCP | 592.36 ms | 181.63 ms |
| DCL | 1.06 s | 138.27 ms |
| L | 1.57 s | 148.83 ms |
日曜の早朝ということもあり、サーバーの負荷が軽い、通信環境がよい、という条件が揃っており、モバイルとデスクトップ共に FCP と LCP にて最速記録を叩き出した。だた早すぎて読み込まなくてもよい記事内の画像も読み込んでしまう。
FCP 1.0 s 、 LCP 1.0 s 、 TBT 20 ms 、 CLS 0 、 Speed Index 1.0 s
高速化に取り組んだ感想
2 か月半弱かけてサイトを高速化しました。 PageSpeed Insights のモバイルでオール 100 点が出ても、強制リフローとレイアウトの再計算が起きるのでそこを潰すのに時間がかかりました。 Gemini に聞きながらでこれだけ時間がかかったので、ひとりでやっていたらどれだけ時間がかかたのだろうと思います。おかげで一瞬で表示されるサイトになりました。多分自分ひとりだったら、 PageSpeed Insights で 100 点が出た時点で多分やめていたと思います。


























