コフス技術ブログ

GulpにてCritical CSSを生成し、PHPで<head>内に出力する簡素な方法

この記事はにメンテナンスが行われています。

ページの描画速度を上げる1つの手段として、<head>内にCSSを直接記述する方法があります。俗に言うCritical CSS(クリティカルレンダリングパスの最適化)です。

クリティカルレンダリングパスとはブラウザがレンダリングする際のペイントを実行するまでの多くのステップの事を指しますが、外部CSS等は読み込みまでの間レンダリングを阻害する為、その後のペインティング作業が遅れてしまいます。

これを解決する為に、外部CSSではなく直接<head>内にファーストビュー分のCSSを記述し描画速度を高め、残りは外部CSSより読み込むといった最適化を行うわけです。

勿論外部CSSのSizeやネットワーク環境、サーバー環境にもよるので一概に外部CSS is 悪とはなりません。
ただしページの描画速度を高める必要性がある場合にはCritical CSSの効果はある程度期待ができます。

Gulp環境でCritical CSSを生成する

まずCritical CSSを生成するにはファーストビュー分のCSSが必要になります。
外部サービス等を利用して毎度コピペする方法もありますが、Gulp環境で構築している場合は自動化してしまうと楽です。

プラグインは様々な物がありますが、今回はgulp-penthouseを利用する方法です。以下のステップを踏みます。

  1. gulp環境で通常通りscssをcssにコンパイルする
  2. コンパイルされたcssを元にgulp-penthouseでファーストビュー分のcssを生成。この時background-imageの様にcssで外部ファイルを読み込む場合はURLを置換してあげる。
  3. 対象のphpファイルにてfile_get_contentsで読み込む

インストール

まずはgulp-penthouseをインストールします。background-imageの様にCSSで外部ファイルを読み込む場合は置換用プラグインもインストールしておきます。(必要な場合)

$ npm i -D gulp-penthouse

# 必要な場合
$ npm i -D gulp-replace

gulpfileよりタスクを追加していきます。既にgulpやgulp-sass等主要プラグインは読み込んでいるものとします。

gulpfile.js
// gulp-penthouseの読み込み.
const criticalCss = require('gulp-penthouse');
// 置換用プラグイン.
const replace = require('gulp-replace');

// Scss コンパイルのタスク.
gulp.task('css', () => {
  // 省略.
});

// criticalCssのタスク.
gulp.task('critical-css', () => {
  return gulp
    .src(output.css + 'style.css') // cssを読み込む.
    .pipe(
      criticalCss({
        out       : 'critical.css', // 生成するCritical CSSのファイル名を指定.
        url       : 'http://cofus.work', // 対象ページのURL.
        width     : 1366, // 横幅.
        height    : 900, // 縦幅.
        userAgent :
          'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' // UA指定.
      })
    )
    .pipe(replace('../', '//cofus.work/assets/')) // 置換(開発環境と本番環境でURL置換が必要な場合はここで置換しておく)
    .pipe(
      css({
        precision   : 5,
        outputStyle : 'compressed'
      })
    )
    .pipe(gulp.dest(output.css + '/css/'));
});

// Watch files
gulp.task('watch', () => {
  gulp.watch(input.css + '**/*.scss', gulp.series('css', 'critical-css'));
});

// Defalut task.
gulp.task('default', gulp.task('watch'));

後は通常通りのタスクでgulpを実行し、scssファイルを更新するとCritical CSSを生成することが出来ます。

npx gulp

上記gulpfile.jsではscssファイルの更新時にタスクが走りますが、Critical CSSの生成には若干時間が掛かる為ある程度の規模の案件であれば別タスクにしてしまうといいでしょう。

Critical CSSを埋め込む

後は生成されたCritical CSSを<head>に埋め込んであげるだけです。file_get_contents等で直接埋め込んでしまうといいでしょう。

head.php
$options['ssl']['verify_peer']      = false;
$options['ssl']['verify_peer_name'] = false;

$critical_css = file_get_contents(
  'https://cofus.work/assets/css/csscritical.css',
  false,
  stream_context_create( $options )
);

<style><?php echo $critical_css; ?></style>

残りのCSSは</body>付近に移動

<head>内に外部ファイルのcssが存在したままだとレンダリングブロックが発生してしまうので、</body>付近まで移動します。

footer.php
<body>
  <script src="bundle.js" defer="defer"></script>
  <link rel="stylesheet" href="style.css">
</body>

同時にjs等も<head>内にあるとレンダリングブロックの原因に繋がる為、同じく</body>付近まで移動してあげます。

以上がCritical CSSを生成し、実際に<head>内に出力する簡素な方法でした。

上記例以外にもCritical CSSを用いたクリティカルレンダリングパスの最適化の方法は幾つかあります。案件に合わせて適切な方法を採用していくといいでしょう。

ただしCritical CSSで出力したCSSの量が物凄く多くては今度は読み込みスピードにも影響してきます。必ずしもCritical CSSがページ描画速度を上げるベストプラクティスでは無い点には注意しておきたいです。