1〜2年程前からページの初期表示速度を早める手段として、「クリティカルCSS」が話題に出てくるようになりました。
アウラのホームページ制作でもパフォーマンス向上のため、去年くらいからコーディング時に組み込んでいます。
少しづつ改良を重ね、ここ最近でようやくまとまってきたのでブログでまとめたいと思います。
「クリティカルレンダリングパス」についてはcolissさんの記事で紹介している内容が詳しいです。
ブラウザがページを表示する際にサーバーからHTMLのレスポンスを受け取ると、スクリーンにピクセルが描画されるまでに多くのステップが必要になります。
ブラウザがページの最初のペイントを実行するために必要とするこのシーケンスは「クリティカル レンダリング パス(Critical Rendering Path)」と呼ばれます。
サイトを初めて訪れたときのファーストビューの表示速度に関わる部分です。
そして、クリティカルCSSとは、クリティカルレンダリングパスに必要なCSSのことです。
要はファーストビューの表示に必要なCSS(スタイル)のことです。
CSSは通常、外部ファイルに記述し、<link>タグで読み込みますが、クリティカルCSSは<head>タグの中の<style>タグにインラインで記述します。
これにより、外部ファイルの読み込みを省いてページの表示速度を早めます。ファーストビューに必要のないスタイルは非同期で読み、初期表示に不要なレンダリングブロック要素をなくします。
サイト内の全ページにクリティカルCSSを使う必要はなく、トップページやブログの記事ページなど、検索からの流入が見込めるページのみ適用する程度で良いでしょう。
ページ1つ1つに、ファーストビューに必要なスタイルを抜き出しインライン記述するのは、後々の更新の負担が大きい割りに効果が見込めるのか、微妙だと思います。
クリティカルCSSはスタイルを記述しているCSSファイルから、ファーストビューに必要なスタイルのみを抜き取り、インラインで<style>タグに記述します。
これを手動で管理・更新しようとするとかなり煩雑な作業となってしまい、現実的ではありません。
SASSやタスクランナーを上手く使い、ある程度自動化して管理するのが現実的な導入手段になるでしょう。
今回、クリティカルCSSを導入するためにSCSSとGulp、PHPを利用しています。
大きな処理の流れを説明すると
まずは通常通りスタイルを書いていきますが、その前にSCSSのファイル構成を考えておく必要があります。
ポイントは、FLOCSSの設計手法をベースに、コンポーネントやブロック、レイアウトレベルのクラスは、クラス単位でファイルを作成すると良いです。これは次の2の工程で、必要なスタイルのみを取り出しやすくするために必要な構成です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
・Critical ・Foundation ・Layout ・Object ┣ Block ┃┣ Header.scss ┃┗ Footer.scss ┃ ┣ Component ┃┣ Button ┃┃┗ Button1.scss ┃┗ Heading ┃ ┗ Heading1.scss ┃ ┣ Project ┗ Utility |
1の構成でCSSを作れたら、今度はクリティカルCSSを使うページ専用のSCSSファイルを作成し、ファーストビューに必要なスタイルが記述されたSCSSファイルを@useで追加していきます。
1で紹介したファイル構成に追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
・Foundation ・Layout ・Object ┣ Block ┃┣ Header.scss ┃┗ Footer.scss ┃ ┣ Component ┃┣ Button ┃┃┗ Button1.scss ┃┗ Heading ┃ ┗ Heading1.scss ┃ ┣ Project ┗ Utility ↓↓↓追加 ・Critical ┗ Top.scss ... トップページ用のクリティカルCSS |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
// Top.SCSS /************************************************ * Foundation ***********************************************/ @use '../foundation/normalize'; /************************************************ * Utility ***********************************************/ /* Theme Common */ @use "../utility"; /************************************************ * Block ***********************************************/ /* Navigation */ @use "../block/b_navigation"; /* Mainimage */ @use "../block/b_mainimage"; /************************************************ * Component ***********************************************/ /* Content */ @use "../component/content/c_content"; /* Typography */ @use "../component/typography/c_paragraph1"; /* Button */ @use "../component/button/c_button1"; /* Headline */ @use "../component/headline/c_headline1"; /* Box (Card) */ @use "../component/box/c_box1"; /* List */ @use "../component/list/c_dlist1"; /************************************************ * Project ***********************************************/ /* Layout */ @use "../project/p_top"; |
ファイルを@useする時に気をつけたいのが、背景画像やフォントなど、相対パスで指定している箇所を書き換える必要があります。
@useであれば読み込み時に「with節」を利用して変数を上書きできるので、パスの指定部分はSCSSの変数使い、上書きできるようにしておきます。
1 |
@use '../component/button/button1.scss' as * with ($resource-path: 'assets/css/'); |
上記のファイルをCSSにコンパイルします。
CSSにコンパイルしたファイルからGulpでインクルード用のPHPファイルを生成します。
CSSファイルをGulpで監視し、変更があればタスクを実行するようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/******************************************* * Critical CSSのPHPファイルを生成 *******************************************/ gulp.task("create-critical-style", function(done) { gulp .src('assets/css/critical/*.css') .pipe(replace(/\/\*.+\*\//g, '')) .pipe(replace(/@charset\s"UTF-8";?/g, '')) .pipe(replace(/\n/g, '')) .pipe(replace(/^(.)/g, '<style>$1')) .pipe(replace(/(.)$/g, '$1</style>')) .pipe(rename(function(path) { path.extname = ".php"; })) .pipe(gulp.dest('include/critical-style/')); done(); }); gulp.task("critical-style", function() { const watcher = gulp.watch(['assets/css/critical/*.css'], gulp.parallel('create-critical-style')); watcher.on('change', function(event) { console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); }); }); |
上記の処理は、コンパイルしたCSSから<style>のタグを追記したり、不要な改行などを省いたりしています。
最後にPHPでインクルードします。
1 2 3 4 5 6 7 |
<?php # Critical Style Css include("include/critical-style/top.php"); ?> <link href="assets/css/theme.css" rel="stylesheet" media="print" onload="this.media='all'"> <?php else: ?> <link href="assets/css/theme.css" rel="stylesheet"> <?php endif; ?> |
theme.cssはサイト内の全てのスタイルを記述しているCSSファイルです。
クリティカルCSSのインクルードファイルがある場合は「media=”print” onload=”this.media=’all'”」という属性を追加して読み込み、それ以外は通常通りに読み込んでいます。
「media=”print”」とすることでブラウザでの閲覧に必要のないファイルと認識され、読み込みの間、レンダリングがブロックされません。
さらに読み込みが完了したタイミングで「onload=”this.media=’all'”」でスタイルが適用されるので、外部CSSファイルを簡単に非同期ロードできます。
また、こちらの外部ファイルにはクリティカルCSSに記述しているスタイルも記述されていても問題ないでしょう。クリティカルCSSに書いてあるから、と言ってスタイルの記述の抜き差しは必要ありません。
以上のような方法でクリティカルCSSを管理します。
ちなみにクリティカルCSSは14KB以内におさめるのが良いらしいので、目安にすると良いでしょう。
サイト制作は1つ1つ微妙に要件やシステムが変わることが多いので、完全に自動化してしまうと案件により調整が難しくなります。
ですので、考える必要のない、ただの作業の部分だけを自動化するようにし、なるべく調整がしやすく、かつ通常のCSSの実装に不都合が出ないことを念頭に置いています。
サイトのパフォーマンスはCSSやJS、サーバー側の処理など、様々な要因が絡んでいますが、クリティカルレンダリングパスを理解することはサイトのパフォーマンスチューニングを考える上で重要な部分になるので、しっかりと理解しておきたいですね。