Cocoonの「CSS縮小化」で逆に肥大化していた話

Network

先日のサーバ移行にあわせて配信まわりを見直した結果、記事ページの転送量がgzip圧縮後で約70KB減りました。計測に使った記事では115KBが42KBになり、63%の減少です。一番効いたのは、何かを足すことではなく、テーマの「CSS縮小化」という高速化のための設定を切ったことです。

きっかけは、Claude Codeへ「記事ページが重い原因を、要素ごとに分解して調べて」と頼んだことでした。返ってきた数字は予想外で、817KBの記事ページのうち、1つの<style>タグだけで671,834バイトと、ページの84%を占めていました。

前回のインフラ編で1行だけ触れた話を、詳しく書きます。

一日でLightsailサーバを最新イメージに移行して、フィード生成を10倍速くした話 – Claude Code実践録(インフラ編)
2026年11月19日に廃止されるAmazon LightsailのBitnami版WordPressブループリントから、Lightsail公式イメージへClaude Codeと無停止で移行した記録。障害の原因究明から性能改善、監視の設置まで、一日分の手順と実測値をまとめました。

ページを要素ごとに集計したら84%がCSSだった

「なんとなく重いな」と感じるだけで放置していたページを、要素ごとに分解して集計させました。

記事ページの構成(raw 817KB)サイズ割合
インライン<style>671,912 B84.0%
インライン<svg>3,793 B0.5%
<script>6,089 B0.8%
本文ほか残り14.7%

<style>の冒頭は.wp-block-accordion{...}。WordPressのブロックCSSが、外部ファイルではなくHTMLに直接埋め込まれています。中身を調べると、サイトに登録されている116種類のブロックすべてのCSSが入っていました。このページが実際に使っているブロックは7種類なので、残る109種類分はこのページでは一度も使われません。

gzipで圧縮しても、このCSSだけで88KB。転送量の77%を占めていました。

原因はCocoonの「CSS縮小化」だった

埋め込んでいたのは、テーマ(Cocoon)の高速化設定「CSS縮小化」(内部名css_minify_enable)でした。この機能はサイト内のCSSを結合・縮小したうえで、外部ファイルではなくインラインで出力します。

116種類のブロックすべてが入っていた理由も、この機能にありました。WordPressには、使用中のブロックのCSSだけを読み込む仕組み(should_load_separate_core_block_assets)があります。ところがCocoonは、CSS縮小化と競合するためにこの仕組みを無効にしていました。結果として、この設定ひとつで「全ブロックのCSSが」「毎ページに」「キャッシュ不可能な形で」埋め込まれていたことになります。

縮小(minify)自体は正しい処理です。問題はインライン出力の方でした。外部ファイルなら初回に1度ダウンロードされてブラウザにキャッシュされるものが、インラインでは全ページ・全訪問で毎回転送されます。数KBのCSSなら リクエスト数を減らせるぶん得ですが、671KBでは完全に逆効果です。

「ブロック個別読み込み」は13%しか効かなかった

直し方は2通り考えられます。使うブロックのCSSだけに絞るか、CSSを外部ファイルに戻してキャッシュさせるか。まず前者を実験させました。

現状ブロック個別読み込み
HTML(gzip後)115,194 B100,235 B(-13%)
ブロック定義116種30種
外部CSS0本0本

使うブロックだけに絞っても13%しか縮みません。重かった原因は、定義が多いことではなく、キャッシュが効かない形で毎回転送されることだったからです。方針は外部ファイル化に決めました。

切った結果

CSS縮小化を無効にすると、CSSは12本の外部ファイルに戻りました。

縮小化ON縮小化OFF
HTML(raw)816,909 B415,500 B
HTML(gzip後)115,178 B47,019 B
インラインCSS671,882 B266,306 B
外部CSS <link>0本12本(gzip後 計78KB)

この78KBの内訳は、Cocoon本体と同梱ライブラリが9ファイル(59KB)、WordPress本体のブロックCSSが1ファイル(19KB)、プラグインが2ファイル(1KB)で、ほぼテーマのCSSです。つまり初回訪問の総転送量は約120KBで、実は以前とほぼ変わりません。

それでも初回から速くなる余地はあります。外部ファイルはHTTP/2で並列にダウンロードされるので、115KBのHTMLを1本の流れで受け取り終えるのを待つより、42KBのHTMLと並列のCSSの方が表示を始めやすいからです。そして、はっきり効くのは2ページ目からです。CSSはブラウザとCloudFrontにキャッシュされて再転送されなくなり、以降は1ページ42KBで済みます。表示崩れがないことは、切り替え前後のレンダリング比較で確認してから反映しました。

ついでに見つかった397KB

計測の副産物がもう1つありました。数式表示ライブラリのMathJax(本体274KB+音声読み上げ用123KB=397KB)が、数式のないトップページを含む全ページで読み込まれていたのです。プラグイン(simple-mathjax)のコードを読ませると、条件判定を持たず、どのページでも読み込む作りになっていました。

このブログで数式を含む公開記事は1本だけです。本文に$$\(があるときだけ読み込む小さなプラグインを作って、その1本では今までどおり数式が表示されることを確認しました。残りすべてのページから397KBが消えます。

ここまでで、計測に使った記事はgzip後42KB。元の115KBから3分の1になりました。なお広告スクリプトの重さは残っていますが、これは収益との交換なので、そのままにしています。

教訓:高速化設定は効果を測ってから使う

「CSS縮小化」という名前だけ見れば、有効にしない理由がありません。私も何年も有効のまま使っていました。それが実際には、ページの84%を占める重りになっていた。設定画面の名前は効果を保証しません。

今回の手順はどれも単純です。ページを要素ごとに集計する、疑わしい設定をOFFにして同じ計測を繰り返す、差分を見る。手でやると面倒なこの往復が、AIに頼むと数分で回ります。高速化プラグインや設定を入れる前に、まず自分のページを数えてみることをおすすめします。

おまけ:この修正で、WordPressが描画する404ページも875KBから319KBに縮みました。それでもまだ重いこのページが、なぜ問題なのかは次の記事で書きます。

読みもしないbotに、WordPressがけなげに875KBの404 Not Foundを配り続けて疲弊していた話
WordPressの404ページは重い上にキャッシュも効かず、脆弱性スキャナのbotへ875KBを配り続けてサーバ障害の引き金になっていたので、Apacheの設定で応答を9バイトまで下げた記録です。

コメント

タイトルとURLをコピーしました