デザインのあれやこれ
http/2で何が変わる?要因となるクリティカルレンダリングパスを紐解く
2015年に承認された新仕様『http/2』のメリットとは?これにはクリティカルレンダリングパスの最適化という要素が深く絡んできます。Webページの描画処理順を最適化し、ユーザの待ち時間を最小化する手法について紹介します。
最近はレンタルサーバのサイトで『http/2対応!』みたいな売り文句を見かける事が多くなったように思います。
はて、http/2とは一体何者なのでしょうか。2.0じゃなくて/2だからhttpとは別物の規格?それともWeb2.0みたいな概念?どんなメリットがあるの?
答えとしては、『1ページ内に多数のコンテンツ要素を含むポータルサイトのようなページ、または動画や多数の画像を含んだ総ファイル容量の大きいページなどに限れば、調整次第では表示がスムーズになり閲覧性が良くなる』といったカンジのものです。なんだこの条件付きの微妙なメリットは!?
これには、クリティカルレンダリングパスという要素が深く絡んできます。
今回はhttp/2とは何者か?という疑問を皮切りに、クリティカルレンダリングパスについての解説を記事にしてみようと思います。
そもそもhttp/2ってなに?
一昔前『Web2.0』なんていう言葉が流行った時期がありましたね。今では全く聞かなくなってしまいましたが。それゆえか、なんちゃら2とか2.0とかいう言葉にはどことなく一時の流行り言葉のようなイメージを持ってしまいますが。
『Web2.0』という言葉に関していえば『今後のWebの発展はこのようになっていくよ』という未来予想図に、わかりやすくIT用語らしいバージョンナンバーを付けて認知を図った、ある種のシンボル的なものだったのかなと捉えています。(実際、昔に比べて現在はこのWeb2.0で提唱されていたような形になっていますから、聞かなくなったのはそういう事なんでしょうかね)
ではhttp/2とは何かというと、これはれっきとした新しい仕様です。
そもそもhttpというのは、HyperText形式のファイルを転送するための通信仕様…要するにWebサイトを見るための接続を指したものですが、現在は主にhttp1.1という仕様が使われています。この仕様をバージョンアップさせたのがhttp2.0=http/2というものです。(なぜ2.0ではなく/2なのかは不明ですが…)
1.1との違いは、CPUのシングルコアがマルチコアに変わったようなイメージに近いですね。
通常のWebページは複数のファイルで構成されています。1つのページを開くためには、そのページを構成する複数ファイルを読み込ませる必要があります。
http1.1の仕様では、基本的にファイルは1つずつしか転送できません。1つ目のファイル転送が終わるのを待ってから、2つ目のファイルを転送…という、シングルタスクのイメージですね。トラックと積み荷に例えて、1台のトラックで何往復もしているイメージでも良いと思います。
これに対し、http/2では複数ファイルを並行して転送できる、マルチタスクな仕様になっています。複数台のトラックで同時に積み荷を運ぶイメージですね。
それでは、http/2によりページ表示が劇的に早くなるか?という点についてです。
複数のファイル転送(httpリクエスト)を平行処理できるとはいえ、Webサーバの応答速度や、そもそもの通信回線の速度を上回ることは決してありえないので、ここがボトルネックとなります。トラックが複数台になっても、発送センターのキャパや道路渋滞によって左右されるイメージですね。
このため、例えば総ファイル数が50枚で総容量5Mのページを開くためにかかる時間は、httpでもhttp/2でもほぼ変わりはありません。
では何が違うかというと、下記のようなhttp/2のメリットを活かせるかがキーになります。
- ファイル転送リクエストに優先順位を指定することができる
- リクエストされていないファイルを転送するサーバプッシュ機能がある
このメリットを利用してWebページの改良に活かすためには、クリティカルレンダリングパスについて理解する必要があります。
Webページ表示までの『待ち時間』を最小化するために
たとえ話になりますが、その昔、スーパーファミコンぐらいまでのテレビゲーム(という言葉ももう使われなくなりましたね)のメディアはロムカセットで、データ読み込みの待ち時間というのはほぼ存在しませんでした。その後、プレイステーション等のCDメディア機が主流になり、読み込みの待ち時間というものをはっきり体感させられるようになっていきました。
中にはヒドいものがあって、当時流行りの格闘ゲームでは、試合の度に1分近いローディング待ち時間があり、テンションがだだ下がりになるようなものもありました。(ゲーム名は伏せておきます!)
そんな中で『リッジレーサー』というゲームは非常にうまい処理をしており、ローディング待ち時間中に『ギャラクシアン』で遊べるんですね。しかもそのギャラクシアンでパーフェクトを取ると隠し要素がゲットできるので、ローディング時間が全く苦になりませんでした。もはや『待ち』の時間ではありませんね。
このような感じで、無くすことの出来ない読み込み待ち時間を『ユーザに体感させない』ようにする、このような手法がWebでも提唱されています。
要するに『ページ全体が読み込み終わるまで何も見ることができない』よりは『読み込み終わった部分から順次見れる』ほうがいいよね、という考え方ですね。
特に、ページ中部〜下部の『後で見る可能性の高い部分』の読み込みは後回しにして、ページ最上部の『一番最初に見る可能性の高い部分』を真っ先に読み込んで表示させてあげれば、ユーザにとって読み込み待ち時間の体感を最小にすることができるということです。
この、ページ最上部の『ユーザが一番最初に見る部分』はファーストビューと呼ばれます。
このファーストビューを最優先で読み込んで先に表示させて、それに続くコンテンツ(ユーザがファーストビューを見終わり、ブラウザをスクロールさせてから見る部分)は後から読み込んで表示させる形にできればベストということです。
では、ファーストビューを最優先表示・続くコンテンツを後処理させるためにはどうすれば良いか?ここで関わってくるのがクリティカルレンダリングパスです。
Webページの表示にかかる処理順:クリティカルレンダリングパス
ブラウザがWebページのデータを読み込んで画面に表示する際の処理順番をクリティカルレンダリングパスといいます。
この言葉が単体で使われることは少なく、だいたいは『クリティカルレンダリングパスの最適化』という形で使われています。Webページ表示の処理順番を最適な形に調整するということですね。
Webページの内容が表示される順番は?
ブラウザにhtmlファイルが読み込まれると、上の行から順番に処理が行われ、画面に表示されていきます。
ならば、ファーストビューが最初に表示されるので何も問題ないじゃないか…と思われますが、ここで2点の遅延ポイントを考慮する必要があります。
- html解析中、外部JavaScriptファイルの読み込みが発生した場合は、JavaScriptファイルの読み込みと実行が完了するまで、html解析は中断される
- html解析中、外部CSSファイルの読み込みが発生した場合は、CSSファイルの読み込みと解析が完了するまで、html解析とJavaScript実行は中断される
Webページ表示処理の優先順位は『CSS>JavaScript>html』といった具合で、並行処理はなされず、優先度の高い処理が完了するまで下位の処理は中断されてしまうんです。
CSSやJavaScript等の外部ファイル読み込みは、基本的にはhtmlのhead内に記述することが多いと思います。記述の構造的には正しくキレイですが、ページ表示の最速化という点においてはアダとなってしまうんですね。
結果的には、CSS・JavaScript等の外部ファイル読み込み・処理が全て完了したあとで、htmlのbody(コンテンツ)解析が始まるという形になってしまっています。
これの改善策として、ファーストビューにかかるCSS・JavaScriptだけをインラインで記述することで、ファーストビューを最速で処理、後続コンテンツの処理を後回しにしてあげます。
<!DOCTYPE html>
<html>
<<head>
<title>クリティカルレンダリングパスの最適化</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }
</style>
</head>
<body>
<p>このページは<span>クリティカルレンダリングパスの最適化</span>練習用ページです。</p>
<div><img src="img_crp_sample.jpg"></div>
<script>
var span = document.getElementsByTagName('span')[0];
span.textContent = 'interactive'; // change DOM text content
span.style.display = 'inline'; // change CSSOM property
// create a new element, style it, and append it to the DOM
var loadTime = document.createElement('div');
loadTime.textContent = 'このページは' + new Date() + 'に読み込まれました。';
loadTime.style.color = 'blue';
document.body.appendChild(loadTime);
</script>
</body>
</html>
(※サンプルコードは参考サイトのものを一部改変して掲載しています)
まず、ファーストビュー部分のスタイルを記述したCSSをインラインで記述します。外部CSSファイルのリクエスト・読み込み、他コンテンツ部のスタイル処理を待たせることなく、最小で最速の処理を行わせます。
次に、ファーストビューのhtmlを記述します。これで、ユーザが最初に目にする部分の表示が最速で行われることになります。
その直後に、ファーストビューにかかるJavaScriptをインラインで記述します(サンプルの場合は、ページを開いた時間を取得してテキストの追加表示処理をさせていますね)。JavaScriptによるDOM操作は、対象となるDOMの処理(表示)が完了していないと、要素が発見できずエラーとなってしまうので、このようにDOM処理後に記述させます。(.onLoadと同じ理由ですね)
こうして、ファーストビューの表示処理が完了したあとで、改めて後続コンテンツ用のCSS・JavaScript外部ファイルの読み込みを行い、後続のコンテンツ表示処理をさせていきます。
懸念事項など
中途半端に表示されていくのは良いこと?
ビジュアルや演出重視のページなら、上記のような最適化処理はむしろしないほうが良い場合もあるかもしれません。
ユーザの待ち時間短縮という点において順次表示は有効なものですが、中途半端に次々と表示されていくので、見栄えとしてはあまり良いとは言えません。『読み込み中』の表示をさせて、全コンテンツの準備が整ったうえで表示させたほうがアピールとして有効な場合もあると思います。ここはケースにあわせて使い分けていきたいところです。
ソース管理の複雑化
クリティカルレンダリングパスの最適化にあたっては、ファーストビューにかかる部分のCSS・JavaScriptが必然的に切り分けられ、今まで1つの外部ファイルにまとめられていたものも2つ以上に分散してしまいます。
また記述箇所もhead内ではなく、ファーストビュー記述後という(ファーストビュー要素の増減に伴って)ぐらぐらと定まらない場所になってしまいます。
長期間運用するサイト・変更や更新が多いサイトにおいては、管理面では面倒なことになりそうです。
また、ファーストビューではjQueryが使えないという点も痛いところです。
正確には、決して使えない事は無いのですが、クリティカルレンダリングパスの最適化の目的は『ファーストビュー描画までを最短距離で行う』ことなので、ファイル容量がそれなりに大きく処理に時間がかかるjQueryの読み込みは必然的に後回しとなり、ファーストビューではjQueryを使わず『生のJavaScript』での処理記述が必須となります。jQueryなら1行で済んでしまう処理を、いまさら十何行もかけて処理を書いていくのは少々しんどいものがありますね。
このような理由もあり、『じゃあこれからは全部ファーストビューだけ先に表示されるようにしよう』とするのも早計かもしれません。当然工数もそれなりにかかってきますし、そもそも1ページ内の要素がさほど多くないページにおいては効果が体感できないものもあると思います。
話はhttp/2に戻り、じゃあどう効果があるの?
話が大きくそれてしまった感がありますが、http/2の件に戻ります。
クリティカルレンダリングパスの最適化とは、前述のように『ファーストビュー要素を最速で読み込み・表示させ、ユーザの待ち時間の体感を最小化させる』ものです。
http/2の新要素である『優先順位を指定してレスポンス処理が可能』『リクエストされていないファイルのプッシュ送信が可能』を用いて、ファーストビューにかかるファイルを優先的に、またリクエストされる前にプッシュ送信をしてやれば、ファーストビュー表示の最速化に役立つ…ということですね。
これが、冒頭で言った『〜〜に限れば、調整次第で〜〜閲覧性が良くなる』という微妙な条件とメリットの所以です。
そもそもの本題を折るようですが、個人的には『効果は極めて小さいもの』じゃないかな…と考えています。
結局は通信速度やサーバー応答速度というボトルネックがあるので、前述のような最適化やhttp/2の導入よりは、読み込むファイル容量を小さくする『画像ファイルの最小化』『画像のSVG化/フォント化』といった手法のほうが効果は大きいと思うんですよね。
これら読み込み容量の最小化(最適化)を全て行ったうえでのクリティカルレンダリングパス最適化・http/2導入…といった立ち位置のものなんじゃないかな?と、そんなふうに捉えています。
参考ページなど
普及が進む「HTTP/2」の仕組みとメリットとは | さくらのナレッジ
JavaScript を使用してインタラクティブにする | Google Developers
http/2の導入・またクリティカルレンダリングパスの最適化は、効果が体感できるシーンがわりと限られるものですが、何かの参考になれば幸いです。