はじめに
はじめまして、ラクスフロントエンド開発課の斉藤です。
普段フロントエンド開発課では、一部のプロダクトにおいて新しく開発した機能を実装した画面や、パフォーマンスの劣化が懸念される画面に対して、性能計測を行っています。今回はフロントエンド開発課がどのようなWebパフォーマンス指標を計測しているのか、なぜその指標を採用したのか、どのように計測しているのかを紹介したいと思います。また、パフォーマンスを計測している中で不便に思っていることや改善していきたいことについてもご紹介します。
注意点として今回紹介する指標や計測ツールは、あくまでもラクスのプロダクトに合わせて選定したものであるため、他社様、あるいは個人にとって最適なものと言えるわけではありません。参考程度にお読み頂ければ幸いです。
対象読者
- フロントエンドのパフォーマンスを計測したいが、どの指標を計測すればよいかわからない方
- フロントエンドのパフォーマンスを計測したいが、どのツールを使って計測すればよいかわからない方
- フロントエンドのパフォーマンス測定について興味がある方
この記事で扱わないこと
- Webパフォーマンスの改善方法
結論
計測する指標と目標スコアの一例
WANT | MUST | |
---|---|---|
FCP | <= 1.8s | <= 3.0s |
LCP | <= 2.5s | <= 4.0s |
TTI | <= 3.8s | <= 7.3s |
TBT | <= 200ms | <= 600ms |
CLS | <= 0.1 | <= 0.25 |
Response | <= 100ms | <= 1000ms |
Animation | <= 16.7ms(60FPS) | <= 33.3ms(30FPS) |
※目標スコアはあくまでも一例になります。実際にはプロダクトごとに異なる値となっています。
計測ツール
パフォーマンス指標計測には以下ツールを用いる
- Chrome devtools: Performance Insight
- 測定対象:FCP, LCP, TTI, CLS
- Chrome devtools: Performance
- 測定対象:TBT, Response, Animation
選定理由
- devtoolsに内包された機能のため実施コストが低い
- ネットワーク・CPUのスロットルが行えるため実ユーザー環境に近い計測が行える
- web.devで紹介されている指標に加え、RAILモデルの測定も行えるため
各指標の概要と選定理由
ユーザーがパフォーマンスをどのように認識しているかに関する指標として、以下の項目が挙げられています。
- 使用可能性:ユーザーがページを操作できているか。ビジー状態になっていないか。
- 快適さ:遅延やエラーがなく、スムーズで自然な操作ができているか。
- 知覚される読み込み速度: ページがすべての視覚要素を読み込み、画面にレンダリングする速度。
- 読み込みの応答性: コンポーネントがユーザーの操作に対してすばやく応答するために、ページが必要な JavaScript コードを読み込んで実行する速度。
- 実行時の応答性: ページの読み込みが完了した後、ページがユーザーの操作にどの程度すばやく応答できるかを示す指標。
- 視覚的な安定性: ユーザーが予期しないような手法でページ上の要素が移動し、ユーザーの操作に支障をきたす可能性があるかどうかを示す指標。
- 滑らかさ: トランジションやアニメーションが一定のフレーム レートでレンダリングされ、ある状態から別の状態へと流れるように移動しているかどうかを示す指標。
フロントエンド開発課では上記を網羅的に測定することを目指し各指標を選定しています。
FCP (First Contentful Paint)
概要
FCPは、ユーザーがアクセスしたウェブサイトで最初に表示されるコンテンツがどれくらい早く描画されるかを示す指標です。この指標における "コンテンツ" は、テキスト、画像 (背景画像を含む)、<svg>
要素、白以外の<canvas>
要素のことを指しています。
上記のタイムラインでは2フレーム目にコンテンツが初めて表示されています。このようにFCPはwebサイトを読み込んでから一部のコンテンツが表示されるまでの時間を計測します。全てのコンテンツがレンダリングされる時間では無いことに注意してください。
選定理由
読み込みの応答性を測定するため
参考スコア
MUST:3秒以下
WANT:1.8秒以下
参考:https://web.dev/fcp/#fcp-における良いスコアとは?
LCP (Largest Contentful Paint)
概要
LCPは、ビューポート内で最も大きなコンテンツがどれだけ早く描画されるかを示す指標です。この指標における "コンテンツ" は、以下の要素を指します。
<img>
要素<svg>
要素内の<image>
要素<video>
要素 (ポスター画像が使用されます)- テキスト ノードやその他のインラインレベルのテキスト要素の子要素を含むブロックレベル要素
- h1, h2, h3
- p
- articleなど
LCPとしてレポートされる要素のサイズは、通常ビューポート内でユーザーに対して表示されるサイズとなります。要素がビューポートからはみ出していたり、要素の一部が切り取られていたり、画面に表示されないオーバーフローが発生したりしているような場合、そういった部分は要素のサイズには含まれません。あらゆる要素において、CSS を介して適用されているマージン、パディング、ボーダーはすべて考慮されません。
上記の例ではLCPは5フレーム目で発生しています。最後の大きな画像が表示されるまではテキスト要素がLCPのターゲットとなっていましたが、ページの読み込みが進み、最終的なLCPのターゲットが変化した例です。
遅れて読み込まれたコンテンツの方がすでにページ上に表示されているコンテンツよりもサイズが大きいといったケースはよく見られますが、必ずしもそうなるわけではありません。次の 2 つの例では、ページが完全に読み込まれる前に LCPが発生しています。
選定理由
知覚される読み込み速度を測定するため
参考スコア
MUST:4秒以下
WANT:2.5秒以下
参考:https://web.dev/lcp/#lcp-における良いスコアとは?
TTI(Time to Interactive)
概要
TTI は、ページの読み込みが開始されてから主なサブリソースの読み込みが完了するまでの指標です。改善することでページがユーザーの入力に対してすばやく確実に応答できるようになります。
TTIは以下の手順に沿って計測されます。
- FCPから時間の計測を開始します。
- 少なくとも 5 秒間の「落ち着いている期間(以下quiet window)」を時間の経過順に探していきます。quiet windowは以下のように定義されています。
- LongTask(50msを超えて実行されるタスク)がない
- 実行中のネットワーク GET リクエストが 2 件以下
- quiet windowより前の期間内で、一番最後に現れる長く時間がかかっているタスクを見つけ出します。長く時間がかかっているタスクが見つからない場合には、FCP まで遡ります。
- quiet windowより前の期間内で一番最後に現れる長く時間がかかっているタスクの終了時間が、TTI となります。(長く時間がかかっているタスクが見つからない場合には、FCP と同じ値になります)。
以下の図は、上記の手順を視覚化したものです。
選定理由
実行時の応答性を測定するため
参考スコア
MUST:7.3秒以下
WANT:3.8秒以下
参考:How Lighthouse determines your TTI score
TBT(Total Blocking Time)
TBTは、読み込みの応答性を測定するために重要となる指標です。ページが確実に操作可能になるまでの間の操作不可能性の重大さの数値化に役立ち、TBT が低ければ低いほどページが確実に使用可能となることを示しています。
メインスレッド上にLongTask(50msを超えて実行されるタスク)が存在する場合、そのメインスレッドは"ブロックされた" とみなされます。"ブロックされた" と表現されるのは、ブラウザーが進行中のタスクを中断することができないからです。したがって、Long Task実行中にユーザーがページを操作した場合、ブラウザーは応答する前にタスクの終了を待たなければなりません。これによりユーザーから見るとページが遅い、または質が低いと感じてしまう可能性があります。
TBTは、FCPとTTIの間で発生する各長いタスクのブロック時間の合計により計算されます。
たとえば、ページを読み込んでいる最中のブラウザーのメイン スレッドの図は、以下のようになります。
上記のタイムライン上には 5 つのタスクがあり、そのうちの 3 つは継続時間が 50 ms を超えているため、長く時間がかかっているタスクとなります。以下の図は、長く時間がかかっているタスクそれぞれのブロック時間を示しています。
このため、メイン スレッドでのタスク実行の総時間は 560 ミリ秒ですが、そのうちの 345 ミリ秒のみがブロック時間としてみなされます。
タスクの継続時間 | タスクのブロック時間 |
---|---|
タスク 1 | 250 ミリ秒 |
タスク 2 | 90 ミリ秒 |
タスク 3 | 35 ミリ秒 |
タスク 4 | 30 ミリ秒 |
タスク 5 | 155 ミリ秒 |
合計ブロック時間 | 345 ミリ秒 |
選定理由
使用可能性、読み込みの応答性を測定するため
参考スコア
MUST:600ミリ秒以下
WANT:200ミリ秒以下
参考:how-lighthouse-determines-your-tbt-score
CLS(Cumulative Layout Shift)
CLSは、視覚的な安定性を測定するための指標です。画面に表示されたコンテンツのユーザーの予期しない突然の移動やズレをレイアウトシフトと呼びます。このレイアウトシフトに遭遇する頻度の数値化に役立つ指標がCLSであり、CLS が低ければ低いほど、そのページが快適であることが保証されます。
CLSスコアは以下の計算式で算出されます。
レイアウトシフトの影響を受けた面積 × 実際にずれて動いた距離
以下のようにテキストが表示されたあとに「Click Me」ボタンが表示され、要素のズレが起こった場合を考えます
レイアウトシフトの影響を受けた面積(赤点線部に囲まれた分)はビューポート全体の50%を占めるため0.5となります。また実際にずれて動いた距離(紫色の矢印の長さ)はビューポート全体の15%を占めます。したがってCLSスコアは次のように計算できます。
0.5(レイアウトシフトの影響を受けた面積)× 0.15(実際にずれて動いた距離)=0.075
レイアウトシフトが複数箇所で発生する場合は上記計算式の合計値がCLSスコアとなります。
参考:https://gmotech.jp/semlabo/seo/blog/cwv_cls/
選定理由
視覚的な安定性を測定するため
参考スコア
MUST:0.25以下
WANT:0.1以下
参考:https://web.dev/cls/#cls-における良いスコアとは?
Response
概要
Responseは、ユーザーがアクションを起こしたときWebサイトが反応するまでを測定する指標です。100ms以内に完了することで、ユーザーはやりとりが瞬時に行われていると感じます。例えば以下のアクション時間を測定します。
- チェックボックスにチェックを入れてからチェック状態が反映されるまで
- リンクをクリックしてから画面が遷移するまで
- ボタンをクリックしてからダイアログが表示されるまで
- APIを叩いてから何らかの通知(スナックバーやトースト等)が表示されるまで
選定理由
快適さ、実行時の応答性を測定するため
目標
MUST:1000ms以下
WANT:100ms以下
参考:https://web.dev/i18n/ja/rail/#ユーザーに焦点を合わせる
Animation
概要
Animationは、アニメーション動作の各フレームの動作時間を測定する指標です。この指標はアニメーションの視覚的な滑らかさを数値化したものです。
選定理由
滑らかさを測定するため
目標
MUST:16.7ms以下
WANT:33.3ms以下
※ それぞれ30FPS/60FPSを満たす目標
参考:https://web.dev/i18n/ja/rail/#アニメーション:フレームを10ミリ秒で生成する
上記以外にも重要な指標としてFIDが挙げられます。FIDは、ユーザーが最初にサイトを操作したとき から、その操作に実際に応答するまでの時間を測定する指標です。この指標は実際のユーザー環境で測定する指標であるため測定難易度が高くなります。したがって、FIDの代わりにTBTを測定することで対処する事とします。TBTはFIDと相関性が高く、かつ検証環境での測定が可能なことが理由です。
計測手順
webパフォーマンス計測環境の準備
webパフォーマンスを計測するために以下の条件を満たす環境を用意します
- 検証環境
- 本番ビルドかつBEと疎通が行える環境を用意します
- ただしフロントエンドのパフォーマンス測定のみに焦点を当てる場合、バックエンドはモック環境でもOKとします。その場合でもフロントエンドは本番ビルドを行った環境で測定してください。
- 理由:ユーザーが使用する実際の環境に近い条件で測定するため
- 本番ビルドかつBEと疎通が行える環境を用意します
- 理論上表示できる最大数のデータを用意する
- 例えば1つのページで最大500件の検索結果を表示できるような仕様の場合、ダミーデータを500件以上用意しかつ、その全てを表示した上で計測を行います
- 最大表示件数が決まっていないページに関しては、ビューポート全体に表示できる数のダミーデータを用意すればOKとします
- 理由:予測される最大のレンダリングコストがかかる環境のパフォーマンス改善を行うことができれば、その画面全体のwebパフォーマンス向上が期待できるため
計測対象画面
- 新しく機能を追加した画面において、パフォーマンスの低下が懸念される画面
- 新しく作成した画面
- 類似した画面を複数実装する場合いずれか1つでOKとします
devtoolsの設定
webパフォーマンスの計測を行う前にdevtoolsの設定を行います。
view portの設定
view portによりwebパフォーマンスの測定結果は変化するためview portを固定します。
devtoolsを開き「Toggle device toolbar」を押下します。
画面サイズを任意の値に設定します。基本的には提供するアプリケーションの推奨する画面サイズに設定します。
スロットルの設定
商材を利用するユーザーが用いるPCはエンジニアの開発用PCと比較して性能が低いことが懸念されます。したがってユーザーの実環境に近い条件でwebパフォーマンスの測定を行うため、devtoolsでスロットルの設定を行います。
devtoolsの「Performance Insights」パネルを開きます。
セレクトボックスを押下しNetwork、CPUを想定するユーザーの環境に合わせて設定します。ユーザーは基本的にキャッシュされた状態のページを参照するので、「Disable cache」のチェックは外します。
同様にdevtoolsの「Performance」パネルを開きます。
設定ボタンを押下します。
CPU、Networkを設定します。
各webパフォーマンス指標の測定
LCP, TTI, LCP, CLSの測定
LCP, TTI, LCP, CLSはChrome DevToolsの「Performance Insights」パネルで測定することができます。
- Chrome DevToolsを開き、「Performance Insights」パネルを押下します。
「Measure page load」を押下しパフォーマンス測定を行います。
devtoolsに表示されるFCP,LCP,TTIにマウスホバーすると各値が表示されます。
CLSは画面にレイアウトシフトが発生している場合のみ自動で計測されます。「Insights」タブから値を確認できます。
TBTの測定
TBTはChrome DevToolsの「Performance」パネルで測定します。
- Chrome DevToolsを開き、「Performance」パネルを押下します。
画面左上の「Start profiling and reload page」を押下します。
devtools下部に表示される「Total blocking time」の値がTBTです。
Responseの測定
ResponseはChrome DevToolsの「Performance」パネルで測定します。
今回はボタンを押してからダイアログが開くまでの応答時間の測定を例にとります。
- Chrome DevToolsを開き、「Performance」パネルを押下します。
- 「Screenshots」にチェックを入れます。
devtools左上の「record」を押下します。
アプリケーション上でボタンを押下し、ダイアログを表示させます。
devtools左上の「stop」を押下します。
スクリーンショットを確認しながらボタンを押してからダイアログが表示されるまでの範囲をドラッグして絞り込みます。
TotalがResponseの測定値になります。
Animation
AnimationはChrome DevToolsの「Performance」パネルで測定します。
今回はダイアログが開く際のアニメーションを測定します。
1~5まではResponseの測定と同様
スクリーンショットを確認しながらアニメーション動作中の各フレームの動作時間を記録する
2で記録した各フレームの動作時間の平均値がAnimationの測定値になります。(1フレームずつ確認するのは非効率なためぱっと見でもOK)
パフォーマンス測定シート
フロントエンド開発課では各webパフォーマンス指標の測定結果を以下のようなスプレッドシートにまとめています。
全測定値のうち75パーセンタイル以下の値が合格基準を満たしていれば、その指標は合格となります。例えば測定回数が全部で4回の場合、そのうちの3回が合格基準を満たしていればOKということになります(参考)。合格基準に満たない場合でも「訳あり合格」として合格とすることもできます。現実的には全ページ、全機能で合格基準を達成することは難しいです。達成が難しく改善できない合理的な理由を説明できるのであれば「訳あり合格」とすることができるようにしています。
現状問題に感じていること
ここまで読んでいただいている場合すでにお察しかもしれませんが、各パフォーマンスを手動で計測しているため実施コストが高いです。少しでも測定コストを減らすため、Animationの指標は測定してなかったり(SaaSプロダクトにおいて重要度の高くない指標のため)、BEをMSWでモックした環境で測定を行うこともあります。信頼性の高いデータを測定することとパフォーマンスを測定するコストはトレードオフの関係にあるので、工数と相談しながら計測しているのが現実です。今後の展望としてLighthouse CIやSentry等を用いて自動的にパフォーマンス測定&レポート作成ができないか検証を進めていきたいです。
パフォーマンス計測を始めてよかったこと
各Webパフォーマンスの指標に基づいて具体的な数値を計測するため、パフォーマンス劣化のボトルネックがどこにあるかを特定しやすくなったので良かったです。「なんとなくページが遅い気がする」といった感覚値から「LCPの値が基準値を◯%下回っているためパフォーマンスが悪い」のように実測値で判断できるようになりました。これにより、このページのパフォーマンスを改善するためにはチャンク分割が効果的なのではないか、と具体的な根拠を持って仮説を立てることができるようになり、効率的に改善に取り組めています。またパフォーマンス改善を行なった後もう一度計測を行うことで、具体的にどの項目がどれだけ改善されたのかがわかるようになったため、パフォーマンス改善のために行なったことが本当に効果があったのか検証するのにも役立っています。
おわりに
ラクスのフロントエンド開発課が測定するWebパフォーマンス指標と測定方法を紹介しました。計測はまだ始めたばかりで非効率な部分も感じています。少しずつ改善しながら実施コストを下げつつ、定期的にパフォーマンス測定を行うことで、より品質の高い製品をリリースしていきたいです。