0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クリティカルCSSインライン化の効果を実装して確認してみた

Last updated at Posted at 2025-01-01

はじめに

クリティカルCSS(ファーストビューで必要なCSS)をHTMLファイルにインライン化する方法があります。本記事ではこの方法によるパフォーマンスへの影響を確認してみます。

ゴール

クリティカルCSSをHTMLファイルにインライン化したパターンと外部ファイルとして読み込むパターンにおいて、Largest Contentful Paint (LCP)の指標を比較し、パフォーマンスの違いを比較してみる。

環境

express:4.21.2

ディレクトリ構造

critical-css-demo/
├── package.json
├── server.js
└── src/
    ├── inline/
    │   ├── index.html
    │   └── styles.css
    └── external/
        ├── index.html
        └── styles.css

クリティカルCSSとは?

キーワード:クリティカル CSS は、ユーザーにコンテンツをできるだけ早く表示するために、スクロールせずに見える範囲のコンテンツの CSS を抽出する手法です。
引用:https://web.dev/articles/extract-critical-css

抽出したクリティカルをHTMLにインライン化して記載する事で、ファーストビューで使用するCSSのリクエストがなくなり、ページの表示を早くできます。

インライン化パターン

クリティカルCSSをHTMLにインライン化して記載してみます。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Critical CSS Demo - Inline Version</title>
    <style>
        .first-view {
            height: 100vh;
            background: linear-gradient(45deg, #1a2a6c, #b21f1f);
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            color: white;
        }

        .first-view-text {
            font-size: 1.5rem;
            margin: 2rem 0;
        }

        .cta-button {
            padding: 1rem 2rem;
            font-size: 1.2rem;
            background: #fff;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: transform 0.3s;
        }
    </style>
    <link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
    <noscript><link rel="stylesheet" href="styles.css"></noscript>
</head> 
<body>
    <div class="first-view">
        <h1>サンプルテキスト</h1>
        <p class="first-view-text">ほげほげテキスト</p>
        <button class="cta-button">サンプルボタン</button>
    </div>
    
    <div class="content">
        <div class="card">
            <h2>カード1</h2>
            <p>スクロールして表示されるコンテンツ</p>
        </div>
        <div class="card">
            <h2>カード2</h2>
            <p>これも初期ビューポート外</p>
        </div>
    </div>
</body>
</html>

参考:

ファーストビュー部分以外のCSS
styles.css
.cta-button:hover {
  transform: scale(1.05);
}

.content {
  padding: 4rem 2rem;
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

.card {
  padding: 2rem;
  background: #f5f5f5;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s;
}

.card:hover {
  transform: translateY(-5px);
}

外部CSS参照パターン

ファーストビューで使用するCSSは外部ファイルに記載します。

index.html
<!DOCTYPE html>
<html>
<head>
    <title>Critical CSS Demo - External Version</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="first-view">
        <h1>サンプルテキスト</h1>
        <p class="first-view-text">ほげほげテキスト</p>
        <button class="cta-button">サンプルボタン</button>
    </div>
    
    <div class="content">
        <div class="card">
            <h2>カード1</h2>
            <p>スクロールして表示されるコンテンツ</p>
        </div>
        <div class="card">
            <h2>カード2</h2>
            <p>これも初期ビューポート外</p>
        </div>
    </div>
</body>
</html>
styles.css
styles.css
.first-view {
  height: 100vh;
  background: linear-gradient(45deg, #1a2a6c, #b21f1f);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: white;
}

.first-view-text {
  font-size: 1.5rem;
  margin: 2rem 0;
}

.cta-button {
  padding: 1rem 2rem;
  font-size: 1.2rem;
  background: #fff;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  transition: transform 0.3s;
}

.cta-button:hover {
  transform: scale(1.05);
}

.content {
  padding: 4rem 2rem;
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}

.card {
  padding: 2rem;
  background: #f5f5f5;
  border-radius: 10px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s;
}

.card:hover {
  transform: translateY(-5px);
}

サーバ側

expressでサーバを準備します。

server.js
import express from 'express';

const app = express();
const port = 3000;

app.use(express.static('src'));

app.listen(port, () => {
    console.log(`
サーバー起動\n
- インライン化パターン: http://localhost:${port}/inline/
- 外部CSS参照パターン: http://localhost:${port}/external/
    `);
});

動作を確認してみる

サーバを立ち上げてブラウザからページを確認します。

npm start

ブラウザでページを開けたので DevToolsでLCPを確認してみます。

ネットワーク速度の違いでどれくらいパフォーマンスが変わるのか興味があったので、スロットリングさせて確認してみました。

スロットリングについて

DevToolsのNetworkタブにある項目で、ネットワーク速度を制限して検証できる機能を指しています。
参考:https://developer.chrome.com/docs/devtools/network/reference?hl=ja#throttling

ここでは測定結果を確認したものを一例として記載しています。

▼ スロットリングなし

  • 外部CSS参照パターン(左画像):0.06s
  • CSSをインライン化したパターン(右画像):0.06s

image.png

スロットリングさせてない状態だとLCP、FCPに差はそんなに見られませんでした。

▼ スロットリングあり

続いてネットワークを高速4Gにスロットリングさせて比較してみます。

  • 外部CSS参照パターン(左画像):0.42s
  • CSSをインライン化したパターン(右画像):0.24s

image.png

外部CSS参照パターンでは、styles.cssがレンダリングのブロッカーになっています。

ネットワークを低速4Gにスロットリングさせて比較してみます。

  • 外部CSS参照パターン(左画像):1.22s
  • CSSをインライン化したパターン(右画像):0.64s

image.png

ネットワークを3Gにスロットリングさせて比較してみます。

  • 外部CSS参照パターン(左画像):4.11s
  • CSSをインライン化したパターン(右画像):2.11s

image.png

CSSをインライン化パターンでは、ファーストビューに必要なCSSがHTMLに直接埋め込まれているため、外部CSSファイルの読み込みを待つ必要がありません。よってstyles.cssがブロッカーにならずFCP、LCPの時間短縮されています。
低速なネットワーク環境で差がみられるのでモバイルユーザーの体験改善に有効かと思いました。

web.devではLCPが2.5s以内を良好なスコアとしこれに収めることを推奨しています。

クリティカルCSSを作成するツール

クリティカルCSSを抽出するツールとして以下のようなものがあります。

  • Critical Path CSS Generator

  • critical

参考:https://web.dev/articles/extract-critical-css#criticalcss

参考

0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?