クリティカルレンダリングパスの最適化


この記事は [ウェブクルー Advent Calendar 2017](https://qiita.com/advent-calendar/2017/webcrew)の11日目の記事です。
昨日は@t-itouさんの「非エンジニア向けにSQLでデータ集計・抽出できる環境を作った話」でした。

---

#はじめに
クリティカルレンダリングパスとは「ユーザーの操作に関連するコンテンツ表示の順位付け」という意味です。
それを「最適化する」というのは、ブラウザがコンテンツを表示するためにしなくてはいけないお仕事と、ユーザーにとって何が一番の利益なのか、のバランスを「最適化する」こと。

ブラウザのお仕事はソースコードをダウンロードしてきて構造を理解して配置をして描画をすること。
ユーザーの利益はコンテンツをいち早く描画されること。

ブラウザが最終的に描画するにはそれぞれのリソースを軽くしてやるとダウンロードも速いというのはとても単純に考えられます。

**・画像の圧縮によく使うオンラインサービス**
Compressor.io（トカゲのやつ） https://compressor.io/
tynyping（パンダのやつ） https://tinypng.com/
JPEGmini（山のやつ） http://www.jpegmini.com/

**・ソースコードの圧縮はGulp等のタスクランナーに走らせると楽**

ここまでは割と一般的によくやる簡単な表示速度の改善。

##■ レンダリングの工程
**1.Loading**
読んでそのままに、HTMLとかCSSとかjavascriptとか画像とかをサーバーからダウンロードする。
HTMLをDOM（Document Object Model）ツリーに変換、CSSをCSSOM（CSS Object Model）ツリーに変換。
※DOMは「ドム」って呼ばれるんだけど、CSSOMはなんて呼ぶ？「クッソム」？？（笑）

**2.Scripting**
javascriptの実行

**3.Rendering**
DOMツリーにCSSを当てる。大きさや位置関係の計算をしてレイアウトを考える。（レンダリングツリーの構築）
この時「header div p a {cssの記述}」 と書かれていた場合、
「headerの中のdivの中のpの中のa」じゃなくて「aのうちのpに入ってるやつのうちのdivに入ってるやつのうちのheaderに入ってるやつ」って考えるらしい。
だからってわけではないけど、cssの指定の仕方はシンプルな方が「ブラウザに優しい」。

**4.Painting**
描画。文字通り画面に色をおいて見た目を作る作業。

これだけの工程を踏んで、晴れて画面にコンテンツが表示されます。

##■ CSSの配信の最適化
ブラウザは外部CSSファイルのダウンロードと処理が完了するまで、コンテンツを画面に描画するのをブロックします。
なので、外部CSSファイルが多いと、コンテンツを画面に表示するのにかかる時間が増えます。

外部CSSリソースが小さい場合は、HTMLドキュメント内に直接挿入できます。
「CSSをこのようにインライン化すると、ブラウザはページのレンダリングを続けることができます。」←！！！

という事は、レンダリングの開始を遅らせることなくCSSを読み込ませるには、全部インライン化してしまえばいいという事になりますが、
実はGoogle PageSpeed Insightではページのスクロールせずに見える範囲が大きすぎることを警告される場合があります。
大きなCSSファイルの場合は、ファーストビューのコンテンツのレンダリングに必要なCSSを特定してインライン化し、
残りのスタイルの読み込みは画面外のコンテンツの後まで遅らせる必要があります。

```html
<html>

<head>
<link rel="stylesheet" href="hoge.css">
</head>

<body>
<p id="hogehoge">ファーストビューとする</p>
<div>ファーストビュー以外のコンテンツ</div>
</body>

</html>
```

↓↓↓↓↓↓↓　これをこうする　↓↓↓↓↓↓↓

```html
<html>

<head>
<style>
#hogehoge {
color: #F00;
}
</style>
</head>

<body>
<p id="hogehoge">ファーストビューとする</p>
<div>ファーストビュー以外のコンテンツ</div>
<link rel="stylesheet" href="hoge.css">
</body>

</html>
```

##■ javascriptの最適化
ブラウザが解析中に外部スクリプトに遭遇すると、解析を中止してそのjavascriptをダウンロードする作業に移ります。
そのたびにネットワークの往復が発生して、ページが表示され始めるまでの時間を遅延させる原因の一つとなります。

CSSの対応方法と同じでファーストビューの表示に関連するjavascriptはインライン化し、それ以外はコンテンツが配信されるまで遅延させておくのが回避策です。
なお、この場合の読み込み時間の改善は上に述べた「CSSの配信の最適化」も併せて行っておく必要があります。

```html
<html>

<head>
<script type="text/javascript" src="hoge.js"></script>
<link rel="stylesheet" href="hoge.css">
</head>

<body>
<p id="hogehoge">ファーストビューとする</p>
<div>ファーストビュー以外のコンテンツ</div>
</body>

</html>
```

↓↓↓↓↓↓↓　これをこうする　↓↓↓↓↓↓↓

```html
<html>

<head>
<script>
var myHoge = document.getElementById("hogehoge");
</script>
<style>
#hogehoge {
color: #F00;
}
</style>
</head>

<body>
<p id="hogehoge">ファーストビューとする</p>
<div>ファーストビュー以外のコンテンツ</div>
<script type="text/javascript" src="hoge.js"></script>
<link rel="stylesheet" href="hoge.css">
</body>

</html>
```

##■ 最後に
これらの一連の作業を施して「ソースコードをダウンロードしてきて構造を理解して配置をして描画をする」と「コンテンツをいち早く描画させる」ができるようになります。
ただ、やったからと言ってソースコードの量が減ることにはならないので、あくまで「最適化できた」という事です。

もちろんそれ以外に運用面での煩雑さがプラスされるとか、ここは絶対に`<head>～</head>`内に読み込ませないとまずいことになるとか、いろいろ出てくるとは思うので、そこから先は各ページ微調整をすることが大前提にはなりますが、弊社のいくつかのページではそれなりにいい結果が出ている事からも、かなり効果はあると踏んでいます。

おしまい

---
ウェブクルーでは一緒に働いていただける方を随時募集しております。
お気軽にエントリーくださいませ。

[開発エンジニアの募集](https://hrmos.co/pages/1004681658307198976/jobs/0000005)
[フロントエンドエンジニアの募集](http://www.webcrew.co.jp/recruit/creative.html)
[データベースエンジニアの募集](https://hrmos.co/pages/1004681658307198976/jobs/0000023)