メニューは見栄えが良い。ドロップダウンアニメーションはスムーズで、ホバー状態は完璧で、モバイルレイアウトはピクセルパーフェクトです。しかし Lighthouse テストを実行するたびに、Google はあなたのCSSがレンダリングをブロックしていると指摘します。モバイルでのLCPは3.2秒で、診断ではレンダリングをブロックするスタイルシートを削除すれば800ミリ秒を節約できると示されています。その意味や、デザインを壊さずに修正する方法が不明確かもしれません。
問題はデザインではなく、配信方法です。ブラウザはドキュメントのhead内のすべてのCSSがダウンロードされて解析されるまで、単一のピクセルも描画しません。メニューが50KBのスタイルシートを読み込み、ネットワークが遅い場合、ブラウザがメニュースタイルを処理している間、ページ全体が空白のままになります。ヒーローイメージは準備完了。見出しも準備完了。ですが、ブラウザがメニュースタイルを処理しているため、見えません。
この記事では、CSSがレンダリングをどのようにブロックするか、どのメニュースタイルが最初に読み込む必要があるか、そしてスタイルシートを分割して、クリティカルな部分を即座に読み込み、残りをページが表示された後に読み込む方法を説明します。
- head内にリンクされたすべての外部CSSファイルは、ダウンロードされて解析されるまでレンダリングをブロックします。
- クリティカルCSS(ファーストビューに必要なスタイル)をインラインで記述すれば、ネットワークの往復がなくなります。
- ほとんどのメニューCSSはクリティカルではなく、初期読み込み時は配置構造とスペーシングのみが必要です。
- ホバー効果、アニメーション、ドロップダウンスタイルは初期描画後に読み込むことができ、ユーザー体験に影響しません。
- 最適化されたメニューは2~5KBのインラインCSSを読み込み、残りを遅延読み込みします。
CSSがクリティカルレンダリングパスをブロックする仕組み
クリティカルレンダリングパスは、ブラウザがHTML、CSS、JavaScriptを画面上の目に見えるピクセルに変換するための一連の手順です。ステップは以下の通りです:HTMLをダウンロード、HTMLを解析、CSSをダウンロード、CSSを解析、レンダリングツリーを構築、レイアウトを計算、ピクセルを描画。
CSSはデザイン上、レンダリングをブロックします。ブラウザは、ドキュメントのhead内のすべてのスタイルシートが完全にロードされて解析されるまで、何も描画しません。これにより、ページが一瞬デフォルトのブラウザスタイルで表示される「スタイルなしコンテンツのフラッシュ(FOUC)」を防ぎます。
メニューの外部スタイルシートを使用した一般的なShopifyストアのタイムラインを示します:
- ブラウザがHTMLをダウンロード(4G上で200ms)
- ブラウザがHTMLを解析し、
<link rel="stylesheet" href="menu.css">に遭遇 - ブラウザが
menu.cssのダウンロードを開始(4G上で40KBファイルは300ms) - ブラウザが
menu.cssのダウンロードと解析を完了(ミッドレンジモバイルで50msの解析時間) - ブラウザがページの描画を開始できる
メニューCSSのみで初期描画までの時間は550msです。テーマのメインスタイルシートを加えると、何も表示される前に1秒以上の遅延が発生します。
Google の web.dev ドキュメントの「レンダリングをブロックするリソース」に関する記事では、すぐに必要ではないCSSを削除または遅延させることが、LCPとFirst Contentful Paintを改善する最も効果的な方法の1つとされています。
クリティカルメニューCSSとは何か
すべてのメニュースタイルが初期描画前に読み込む必要はありません。レイアウトシフトなしにファーストビューのメニューをレンダリングするために必要なスタイルのみがクリティカルです。それ以外はすべて後で読み込むことができます。
クリティカル(最初に読み込む必要がある)
- レイアウト構造: display プロパティ、flexbox/grid ルール、メニューコンテナのポジショニング。
- スペーシング: 正しい量のスペースを確保するための padding、margin、height、width。
- 基本的な可視性: display/visibility ルールによってメニューが正しい場所に表示されるようにします。
- フォントサイズと行の高さ: 完全なスタイルシートが読み込まれたときのテキストリフローを防ぎます。
非クリティカル(後で読み込める)
- 色と背景: メニューは初期段階でデフォルト色でレンダリングでき、レイアウトシフトは発生しません。
- ホバー効果とトランジション: これらはインタラクション時にのみ適用され、初期読み込み時には適用されません。
- ドロップダウンスタイル: デスクトップではドロップダウンはユーザーがホバーするまで非表示です。モバイルではユーザーがハンバーガーをタップするまで非表示です。これらのスタイルはページが表示された後に読み込むことができます。
- アイコンと装飾要素: メニューシェブロン、区切り線、バッジスタイルはすべて初期描画に必須ではありません。
目標は、レイアウトシフトを防ぐのに十分なCSSをインラインで記述し、残りを遅延させることです。
クリティカルCSSをインラインで記述する:時期と方法
インラインCSSは、外部ファイルにリンクするのではなく、HTML内の<style>タグに直接記述することです。これにより、レンダリング遅延の主な原因であるネットワークの往復がなくなります。
ナビゲーションメニューのクリティカルインラインCSSの例を示します:
<style>
.menu-container {
display: flex;
align-items: center;
height: 60px;
padding: 0 20px;
}
.menu-nav {
display: flex;
gap: 24px;
}
.menu-link {
font-size: 16px;
line-height: 1.5;
text-decoration: none;
}
@media (max-width: 768px) {
.menu-nav { display: none; }
.menu-toggle { display: block; }
}
</style>
これはおよそ300バイトです。メニュー用に正しいスペースを確保し、レイアウトシフトを防ぎ、ページが描画される前にメニュー構造が適切に配置されていることを確認します。残りのメニュースタイル(色、ホバー効果、ドロップダウンアニメーション)は、初期描画後に外部スタイルシートから読み込まれます。
いつインラインにするか
以下の場合、クリティカルCSSをインラインで記述します:
- CSSが小さい場合(目安として5KB以下)。
- スタイルがすべてのページのファーストビューコンテンツに必要です。
- ネットワークレイテンシーが解析コストより大きい負担である場合。
ナビゲーションメニューの場合、インラインはほぼ常に正しい選択肢です。メニューはすべてのページに表示され、クリティカルなスタイルのサブセットは非常に小さいです。
いつインラインにしないか
以下の場合、CSSをインラインにしないでください:
- スタイルシートが大きい場合(10KB以上)。大規模なインラインCSSはHTMLを肥大化させ、HTML解析を遅くする可能性があります。
- スタイルが特定のページにのみ必要です。ページ固有のCSSをすべてのページにインラインすると、帯域幅が浪費されます。
- CSSが頻繁に変更されます。インラインCSSはキャッシュされず、HTMLの一部であるため、すべてのHTMLリクエストにCSSが含まれます。
画像、複雑なアニメーション、複数のレイアウトモードを含むメガメニューなど、広範なスタイルを持つメニューアプリの場合は、レイアウト構造のみをインラインで記述し、残りを遅延させます。
非クリティカルCSSをレンダリングをブロックせずに読み込む
クリティカルCSSを特定してインラインで記述したら、次のステップは、残りのCSSをレンダリングをブロックせずに読み込むことです。一般的な2つのアプローチがあります。
アプローチ1:プリロードとスワップ
<link rel="preload"> を使用してスタイルシートをバックグラウンドでダウンロードし、その後非同期で適用します。
<link rel="preload" href="menu.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="menu.css"></noscript>
preload はブラウザに menu.css を高優先度でフェッチするように指示しますが、レンダリングはブロックしません。onload イベントは rel="preload" を rel="stylesheet" に変更し、ファイルのダウンロード完了後にスタイルを適用します。<noscript> フォールバックにより、JavaScriptが無効な場合でもスタイルが正常に読み込まれます。
このアプローチは広くサポートされており、すべての最新ブラウザで動作します。
アプローチ2:メディアクエリのトリック
マッチしないメディアクエリでスタイルシートを読み込み、読み込み後に all に変更します。
<link rel="stylesheet" href="menu.css" media="print" onload="this.media='all'">
media="print" 属性はブラウザにこのスタイルシートは印刷用のみであると伝えるため、画面レンダリングはブロックしません。ファイルが読み込まれると、onload イベントはメディアクエリを all に変更し、スタイルを画面に適用します。
これはハックですが、確実に機能し、プリロードアプローチより少ないJavaScriptが必要です。
メニュースタイルシートの分割
ほとんどのShopifyメニューアプリは、レイアウト、色、アニメーション、レスポンシブブレークポイント、アイコンスタイルを含む1つのモノリシックなCSSファイルで配供されます。クリティカルパスを最適化するには、このファイルを2つの部分に分割する必要があります:クリティカルと非クリティカル。
実践的なワークフローを示します。
ステップ1:クリティカルセレクターの特定
Chrome DevTools を開き、Coverage タブ(その他のツール下)に移動して、ページをリロードします。Chrome は初期描画中に使用されるCSSルールを表示します。それ以外はすべて非クリティカルです。
ナビゲーションメニューの場合、クリティカルセレクターは通常以下を含みます:
.menu-container、.menu-nav、.menu-logo- レイアウトプロパティ:
display、flex、grid、position、width、height、padding、margin - ファーストビューレイアウト用のレスポンシブブレークポイント
ステップ2:クリティカルCSSを抽出
クリティカルセレクターを新しいファイル menu-critical.css にコピーします。ミニファイします(空白とコメントを削除)。結果は2~5KBである必要があります。
ステップ3:クリティカルCSSをインラインで記述
menu-critical.css をテーマの <head> 内の <style> ブロックに変換します。Shopify Liquid では:
<style>
{% include 'menu-critical.css' %}
</style>
またはCSSをHTMLの <style> タグに直接貼り付けます。
ステップ4:完全なスタイルシートを遅延させる
前述の方法のいずれかを使用して、完全な menu.css を非同期で読み込みます。
<link rel="preload" href="menu.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
これで、クリティカルレイアウトスタイルは即座に(ネットワーク遅延なく)読み込まれ、残りのスタイルはページをブロックせずに並行して読み込まれます。
Shopify固有のCSS最適化
Shopify テーマは file.css フィルターを使用してCSSを読み込みます。デフォルトでは、これは標準の <link rel="stylesheet"> タグを生成します。これはレンダリングをブロックします。
スタイルシートをブロックなしにするには、フィルターを手動タグで置き換えます:
<link rel="preload" href="menu.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="menu.css"></noscript>
CSSを動的に読み込むテーマセクションの場合、Shopify の Section Rendering API は自動的にプリロード戦略を適用しません。メニューがセクションの場合、クリティカルCSSがセクション独自のスタイルシート内ではなく、メインの theme.liquid ファイルにインラインされていることを確認する必要があります。
Navi+ のような一部の Shopify メニューアプリは、CSSを自動的にクリティカルと非クリティカルな部分に分割し、非同期読み込みを処理します。現在のメニューアプリがこれをサポートしていない場合、開発者に追加を依頼するか、既にサポートしているツールに切り替える価値があります。
影響を測定する
メニューCSSを最適化する前後に、Lighthouse または PageSpeed Insights で改善を測定します。3つの特定のメトリクスに注目してください:
- First Contentful Paint(FCP): 最初のテキストまたは画像が表示された時刻。クリティカルCSSをインラインで記述すると、レンダリングをブロックするネットワークリクエストを削除してFCPを短縮します。
- Largest Contentful Paint(LCP): 最大の可視要素の描画完了時刻。レンダリングをブロックするCSSを削除すると、ヒーローイメージまたは見出しがより早く描画されます。
- Cumulative Layout Shift(CLS): ビジュアル安定性の指標。適切にインラインされたクリティカルCSSはメニューのスペースを確保し、読み込み時のページコンテンツの下方へのシフトを防ぎます。
非クリティカルメニューCSSを遅延させた後、モバイルでFCPとLCPが200~600ms低下します。改善が見られない場合は、最適化が必要な他のレンダリングをブロックするスタイルシート(テーマCSS、アプリCSS)がないか確認します。
よくある誤り一部のマーチャントはレンダリング遅延を排除するために、メニュースタイルシート全体をインラインで記述していますが、ファイルが大きい場合は逆効果になります。50KBのインラインスタイルシートはHTMLを肥大化させ、HTML解析を遅くさせ、CSSがキャッシュされることを防ぎます。クリティカルなサブセット(2~5KB)のみをインラインで記述し、残りを遅延させます。
モバイルの方が重要です
デスクトップ接続は高速です。ブロードバンド上の40KBのCSSファイルは、おそらく50ミリ秒の遅延を追加するだけです。モバイルでは、4G接続上の同じファイルが300ミリ秒を追加します。遅い3G接続では、800ミリ秒を追加することもできます。
Google の Core Web Vitals はモバイルとデスクトップで個別に測定され、ほとんどのトラフィックはモバイルであるため、検索ランキングではモバイルの方が重く加重されます。モバイル用のメニューCSS最適化はオプションではなく、基準線です。
実際のデバイス上で実際のモバイル接続でストアをテストするか、スロットリングを有効にした Chrome DevTools を使用します(Fast 3G または Slow 3G)。レンダリング遅延CSSの真のコストが見え、インラインと遅延による改善が明らかになります。
良好なメニューCSS読み込みの見た目
最適化されたナビゲーションメニューは、CSSを2段階で読み込みます。まず、レイアウト構造、スペーシング、レスポンシブブレークポイントを定義する小さなインラインブロック(2~5KB)です。これはHTMLの一部として即座に読み込まれます。次に、色、ホバー効果、アニメーション、ドロップダウンスタイルを含む完全なスタイルシート(30~50KB)を、preload またはメディアクエリのトリックを使用して非同期で読み込みます。
遅いモバイル接続でも、ページは1~2秒以内に表示されます。メニューは正しい位置に表示され、レイアウトシフトは発生しません。完全なスタイルはその数分の一秒後に適用され、ユーザーにはほぼ認識されませんが、Google の LCP 計算では測定可能です。
これは理論的ではなく、このパターンを実装するストアは通常、モバイルLCPが400~700ミリ秒改善し、Core Web Vitals レポートで「改善が必要」から「良好」に移行します。メニューはまったく同じように見え、機能しますが、ブラウザはページを描画する前に完全なスタイルシートを待つ必要がなくなります。
この記事は、メニューとLCP:ナビゲーションがLargest Contentful Paintに与える影響に関するより大きなガイドの一部です。