はじめに
みなさんこんにちは。株式会社アルムの研究開発部 メディカルソリューション開発グループに所属しております、宮永健二と申します。
以前、社内の勉強会で、Webページの表示をいかに早くするかということや、ブラウザのレンダリングの仕組みについて資料を作ったことがあるのですが、今回Engineering Blogの記事を書く機会をいただいたので、それらの情報をアップデートしつつ、まとめてみたいと思います。
Googleが発表したFID→INPについて
今年(2023年)5月、Googleがユーザーエクスペリエンス測定に用いている「Core Web Vitals」の3つの指標(LCP, FID, CLS)のうち、応答性を測定する「First Input Delay(FID)」の代わりに、今後は「Interaction to Next Paint(INP)」を推進していく予定であると発表がありました。 [ Google検索セントラル: INP を Core Web Vitals に導入 ]
今回の記事では、INPをはじめとするWeb Vitalsの指標とは何かを紐解きながら、Webブラウザがサーバーからデータを受け取り、ユーザーインターフェースを通してユーザーに情報を届けるまでのプロセス、その最適化について、まとめてみたいと思います。
Core Web Vitalsとは
Webサービスを利用するとき、いかに役立つコンテンツがあっても、いかに便利な機能が提供されていても、こちらからのリクエスト(操作)に対する反応が遅かったり、リクエストに対する処理の状況がわかりにくかったりすると、ユーザーはストレスを感じるものです。
巷間で一流と言われるサービスは、そういった部分をとことんまでチューニングしていますので、少しでもストレスを感じさせてしまうサービスは、どうしても見劣りしてしまいます。
Googleは、Webサービスのユーザーエクスペリエンスについて大きな革命を成し遂げた世界初の組織だと筆者は思っているのですが、そのGoogleが先導し、2020年にCore Web Vitalsを策定しました。
Web Vitalsの指標群は、ページの読み込み速度やレスポンスの速さなど、ユーザーエクスペリエンスに直結する指標を集めたもので、Webサイトの開発者がパフォーマンスを改善するための目安となります。その中から重要なものを3つ選りすぐったものが、Core Web Vitalsと呼ばれます。
Googleは、Web VitalsによってWebサイトのユーザーエクスペリエンスが向上し、訪問者数が増えることを期待していました。GoogleはWebに広告を出してそれを収入源としているため、こういった取り組みは事業のための自然な行動ではあると思うのですが、それにしてもWebへの貢献が大きすぎると感嘆せずにはいられません。
Core Web Vitalsについてさらに知りたい方は こちらの記事(Web Vitals) を読んでみてください。INPをはじめとする各指標については、のちほど章をあらためて。
PageSpeed Insight
ここで、 PageSpeed Insights というツールをご紹介します。Web Vitalsの指標ごとに計測し評価してくれるものです。試してみたいサイトのURLを入力して、計測してみてください。
そしてこちらが、我らが アルム社HP の評価です。なんと不合格でした!! (T_T) ガーン
チクショー!原因はどこにあるのでしょうか。
Webブラウザのレンダリングについて
少し脇道に逸れますが、Webブラウザのレンダリングについて、ここで軽くおさらいしたいと思います。
普段見ているWebページが、HTMLやCSSなどいった言語で記述されたテキストだらけのソースコードの組み合わせから成り立っていることは、皆さんご存知だと思います。では、そのソースコードをブラウザが解釈して、どういったプロセスで、目に見えるコンテンツとして画面に表示させているのか、その仕組みはご存知でしょうか。
ここで言うレンダリングとは、すなわち「画面描画」のことですが、収集したHTML/CSS等各種リソースの記述内容を解釈し、レイアウトを計算したものを、ディスプレイ上の物理的な一つ一つのピクセルの発色まで落とし込み、目に見える形でユーザーが閲覧・操作するための画面を描画し、表示することです。
なお、今回取り上げるのはChromeやSafariなどのビジュアルブラウザをメインとしていますが、音声ブラウザやテキストブラウザにも適用できる部分は多いと考えます。
そしてレンダリングエンジンとは、前述の画面描画を実行するプログラムです。主なレンダリングエンジンとして、Gecko(Firefox)、WebKit(Safari)、Blink(Chrome・Edge・Opera)などがあります。
レンダリングエンジンの内部構成について、例えばWebKitに含まれる主なコンポーネントには、WebCoreと呼ばれるHTMLおよびSVGを扱うコンポーネントと、JavaScriptCoreというJavaScriptの動作環境を提供するエンジンがあります。
レンダリングエンジンは、Webサーバーなどから受け取ったバイトコードの羅列を、以下のような手順で処理します。
- HTMLマークアップを解析処理してDOMツリーを構築する。
- CSSマークアップを処理してCSSOMツリーを構築する。
- JavaScriptを実行する。
- DOMとCSSOMを組み合わせてレンダリングツリーを構成する。
- レンダリングツリーでレイアウトを実行して各ノードの形状を計算する。
- 各ノードを画面にペイントする。
シンプルに見えるページでも、実はそれなりの量の処理が必要です。DOMまたはCSSOMが変更されると、このプロセスを繰り返して、画面上で再レンダリングが必要なピクセルを判別する必要があります。
前述の6段階のシーケンスは、レンダリングのためのクリティカル・パス、すなわちクリティカル・レンダリング・パスと呼ばれ、これを最適化することで、全体の所要時間を最小限に抑えることができます。 その結果、なるべく短い時間で画面にコンテンツをレンダリングできるようになり、初回レンダリング後の画面の更新間隔も短くなります。つまり、インタラクティブなコンテンツの場合に、高いリフレッシュレートを実現できます。
参考URL:
Core Web Vitalsの各指標について
さて、レンダリングについて確認が終わったところで、先ほどご紹介したPageSpeed Insightで測定される、Core Web Vitalsを含む6つの各指標について解説していきます。
前半3つがCore Web Vitalsの指標、後半3つがWeb Vitalsの中でも重要とされている指標です。なお、執筆時点ではINPは後者に含まれます。
1. Largest Contentful Paint (LCP)
「Largest Contentful Paint (最大視覚コンテンツの表示時間、LCP) は、知覚される読み込み速度を測定するための重要なユーザーを中心とした指標です。これは、LCP がページの読み込みタイムラインにおいてページのメイン コンテンツが読み込まれたと思われる時点を示すためです。」[ Largest Contentful Paint (LCP) ]
LCPが短いというのは、Slackにいる人で例えると、テンプレ的な前置きなしで、簡潔にまとめた要点を最初に書いてくれる人、みたいな感じかもしれません。
ひと昔前は、画面に表示されるコンテンツ全体の描画が完了するまでの時間をいかに短くするか、という考えがあったと思いますが、LCPは、ページが提供するメインのコンテンツだけ真っ先にユーザーにデリバリーして、付随するコンテンツは後追いで読み込み、描画していく、という考えです。
例えばYouTubeの場合、一番早くユーザーに届けたいのは動画コンテンツとプレイヤーですよね。なので、実際に動画のページをブラウザで表示させてみると、まずプレイヤーが表示されて動画のローディングが始まり、続いてページ上部の検索窓やプレイヤー下の動画情報、画面右側の関連動画や、下手するとYouTubeのロゴはずっと最後の方にやっと表示される、といった具合に、ページ内のパーツによって、ユーザーに届ける優先順位を意図的に操作しているらしいということが観察できると思います。
2. First Input Delay (FID)
「First Input Delay (初回入力までの遅延時間、FID) は、読み込みの応答性を測定するための重要なユーザーを中心とした指標です。これは、応答のないページを操作する場合のユーザー体験を数値化したものであり、FID が短ければ短いほど、そのページがユーザーにとって使いやすいものであることが保証されます。」[ First Input Delay (FID) ]
導入部分で触れた、今回Core Web VitalsでINPに取って代わられることになる指標です。
ページの読み込みが始まってから、画面上のコンテンツやコントロールの描画が始まりますが、そこから何かしらのインタラクションが可能になるまでの時間、言い換えると、何らかの意味を持つ操作(リンクやボタンのクリック、文字の入力、フォームコントロールの操作)が可能になるタイミングです。
例えば、ずっとローディングのぐるぐるが表示されていたり、何か色々と表示はされてるんだが、どこをクリックしても反応してくれない、みたいな場合は、FIDが長すぎてユーザーに良い体験を提供できていないことになります。
なお、この指標はあくまで、ページロード後最初の操作が可能になるまでの時間を計測するものです。
Slackにいる人で例えると、こちらから質問した時に、なんか色々とリアクションはしてくれるんだが、けっきょく質問には答えてくれない人がいますが、そういう人はFIDが長いです。つらい。
3. Cumulative Layout Shift (CLS)
「Cumulative Layout Shift (累積レイアウト シフト数、CLS) は、視覚的な安定性を測定するための重要なユーザーを中心とした指標です。これは、ユーザーが予期しないレイアウト シフトに遭遇する頻度の数値化に役立つ指標であり、CLS が低ければ低いほど、そのページが快適であることが保証されます。」[ Cumulative Layout Shift (CLS) ]
これだけ読んでもどういうことかピンとこないかもしれませんが、あなたがページ内のテキストを読んでいて、読んでいた場所の上の方に非同期で広告バナーが読み込まれるなどして、読んでいた部分が突然ガタッと下の方に移動してしまい、視線が迷子になってしまった、という経験はないでしょうか。下手をすると、クリックしようとしていたボタン等の位置がずれて、別のボタンをクリックしてしまったり、意図してない操作をしてしまうこともあります。
ページ内のパーツごとの読み込みや描画を非同期で実行する設計の場合、気を抜いてしまうとこういう罠にハマりそうです。画面のレイアウトがたびたび変化してしまうようなことはなるべく避けましょう。
Slackでの例えはうまく思いつけないのですが、弊社でSlack導入前に使っていたMicrosoft Teamsは、スレッドに貼り付けた画像やリンクのプレビューがこのような挙動を引き起こすことがしょっちゅうで、非常にストレスだったことを思い出します。子会社になってよかったあー!
4. First Contentful Paint (FCP)
「First Contentful Paint (視覚コンテンツの初期表示時間、FCP) は、知覚される読み込み速度を測定するための重要なユーザーを中心とした指標です。これは、FCP がページの読み込みタイムラインにおいて最初にコンテンツが読み込まれたと思われる時点 (ユーザーが画面上に何らかのコンテンツが表示されたことを確認するタイミング) を示すためです。FCP を高速にすることで、そのページが動作していることをユーザーに確信させることができるようになります。」[ First Contentful Paint (FCP) ]
LCPは、ページの読み込みが始まってからメインコンテンツの描画が完了するまでの時間でしたが、こちらはページ読み込み開始以降最初の、何かしらユーザーにとって意味のあるコンテンツの描画が終わるまでの時間を計測します。
FCPが長い人をSlackにいる人で例えると、Emojiでまめにリアクションしてくるんだけど、表情や意図や気持ちが全然読めない人、でしょうか。さっさと具体的にわかるように伝えてほしい…
5. Interaction to Next Paint (INP)
「Interaction to Next Paint (次の描画へのインタラクション、INP)は、2024年3月にFirst Input Delay (FID)に取って代わる予定のCore Web Vitalsの指標です。INPは、Event Timing APIからのデータを使用して応答性を評価します。インタラクションによってページが応答しなくなると、ユーザーエクスペリエンスが低下します。INPは、ユーザーがページと行ったすべてのインタラクションの待ち時間を計測し、その最大値を報告します。INPが低いということは、ページが一貫して、ユーザーのインタラクションのすべて、あるいは大部分に素早く応答できたことを意味します。」[ Interaction to Next Paint (INP) , DeepL+著者訳]
導入部で触れた、Core Web VitalsにおいてFIDに取って代わることになった指標であり、この記事のメイントピックでもあります。
INPスコアが優秀な人をSlackにいる人で例えると、何か作業を依頼した時に、とりあえずEmojiで「読んだよ!」というリアクションをくれる人や「確認します!」「今は忙しいですが、1時間後に着手できます!」とすぐにリプライしてくれる人と、いつまで待ってもリアクションもリプライもしない人がいます。よしんば後者の方が作業完了までの時間が短かったとしても、先に何かのリアクションを見せてくれて、依頼が伝わったこと、着手したことなど、相手のステータスを認知するためのコストが低い人の方が安心すると思います。もちろん作業や報告も含めてトータルで早いのが一番で、INPは処理時間や結果表示までの時間も評価対象に含まれます。
FIDがページロード後最初のインタラクションが可能になるまでの時間だったのに対し、INPはページ滞在中にユーザーが行うすべてのインタラクションに対し、インタラクション可能になるまでの時間、処理にかかった時間、結果を表示し終わるまでの時間を計測します。
ページは、ユーザーの入力が完了・確定した瞬間(keyup, mouseup, pointerup, click 等のイベント発火時)に、入力を受け取ったことをまずはユーザーにわかる形で速やかにフィードバックしなければいけません。そうしないと、うまく操作できなかったかも?という印象をユーザーに与えてしまい、入力を問題なく受け取っていたにも関わらず、ユーザーが同じ操作をやり直す、という行動を誘発してしまいます。そしてもちろんですが、リクエストの処理の処理も無駄なく速やかに実行し、結果をユーザーに届けるべきです。
こういったインタラクションが、ユーザーがページに滞在している間に複数回発生すると思いますが、INPにおいては、それらすべてを計測します。このことで、INPはFIDに比べ全体的な応答性について信頼性の高い指標となります。
INPは、マウスカーソルのホバーやページのスクロールについては計測しません。それでも、クリッカブルなオブジェクトにマウスオーバーした際は、何かしらフィードバックがあった方が(もちろん、うるさくない範囲で)親切だと思いますし、スクロールによってコンテンツが変化するようなページの場合も、遅延なく変化が追従するのが好ましいでしょう。
なお、ページ滞在中のすべてのインタラクションを計測すると書きましたが、例外的な遅延がある程度の割合発生することは許容され、50回につき1回の最も遅延したインタラクションは無視されるようです。
6. Time to First Byte (TTFB)
「Time to First Byte (TTFB) は、ラボでも現場でも、接続のセットアップ時間とウェブサーバーの応答性を測定するための基本的な指標です。TTFBは、ウェブサーバーがリクエストに応答するのが遅すぎる場合に特定するのに役立ちます。ナビゲーション・リクエストの場合、つまりHTMLドキュメントに対するリクエストの場合、他のあらゆる意味のあるローディング・パフォーマンス測定基準よりも優先されます。」[ Time to First Byte (TTFB) , DeepL+著者訳]
Slackで例えると、端末が重かったりネットワークの状態が悪く、そもそもSlackでメッセージを送ったり読み込んだりすることすら難しい、というような状況です。情シスに相談しましょう。
サーバーから受け取るデータの最初の1バイトまでの時間、ということなので、完全にインフラ側の問題になります。下の図はブラウザのリクエストが発火されてからページのロードが終わるまでのフローですが、これだけのイベントが発生しています。
何がいけなかったのか?
ページ読み込みやレンダリングの様子については、Google Chromeの開発者ツールの「ネットワーク」や「パフォーマンス」タブで詳細な解析を確認することができます。視覚的にも面白いと思いますので、ぜひみなさん試してみてください。以下はパフォーマンスタブを開いたところです。
ちなみに、サイトの作りがやばすぎると話題になっていたデジタル庁の場合はこうなります(以下の図)です。整然としています。
解析されたデータを見ながらチューニングを施していくにあたっては、先ほどのPageSpeed Insightsの結果画面には「パフォーマンスの問題を診断する」というセクションがあり、そこで改善案のヒントを得ることができます。
例えば www.allm.net の結果からは
- 最初のサーバー応答時間を速くしてください
- メイン ドキュメントのサーバー応答時間は、他のすべてのリクエストに影響するため、速くする必要があります。
- WordPressテーマ、プラグイン、サーバー仕様はすべてサーバーの応答時間に影響します。より最適化されたテーマを探す、最適化プラグインを慎重に選ぶ、サーバーをアップグレードすることをおすすめします。
- レンダリングを妨げるリソースの除外
- ページの First Paint をリソースがブロックしています。重要な JavaScript や CSS はインラインで配信し、それ以外の JavaScript やスタイルはすべて遅らせることをご検討ください。
- 重要なアセットをインラインで読み込むまたは重要度が低いリソースの読み込みを遅らせるために役立つ、さまざまな WordPress プラグインがあります。ただし、これらのプラグインの最適化処理によって、テーマやプラグインの機能が阻害されることがあります。その場合は、コードを変更する必要があります。
などのヒントを得ることができます。
他にもいろいろと指摘事項ありますが、割愛します。興味がある方は このリンク からご覧いただけます。
まとめ
いかがでしたか?今回は改善についてのヒントを得たところで終わりですが、ユーザーにストレスをかけないようにする、気持ちよく使ってもらう、ということの重要性は、わかっていても現実的になかなか手が回らないところなんじゃないかなと思います。今回の記事が、みなさんの今後のお仕事のお役に立つといいなと思います。
個人的な意見としては、開発する側は高スペックマシン+回線スピードも申し分ない、というぬくぬくとした環境で作ることが多いと思うので、そうではない環境を再現して確認してみる、というのは見逃されやすいポイントかなと今までの経験から思っています。
他にも、ユーザーがなるべく早く正確に目的を達成できるように、操作を簡略化したり、手数を減らしたり、テキストを簡潔にしたり、ユーザーの目線で思いやりを持って改善できる部分は色々あるはずです。
ここまでお付き合いいただき、ありがとうございました。それではまたどこかでお目にかかりましょう。
最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。