あらゆる場所で高速サイトを作成することは一筋縄ではいきません。膨大な数のデバイス機能と、それらが接続するネットワークの品質から、乗り越えられないタスクのように思えるかもしれません。ブラウザの機能を利用して読み込みのパフォーマンスを向上させることはできますが、ユーザーのデバイスの能力やネットワーク接続の品質を確認するにはどうすればよいでしょうか。この問題を解決するには、クライアント ヒントを使用します。
Client Hints は、ユーザーのデバイスとユーザーが接続しているネットワークのこれらの側面に関する分析情報を提供する、オプトイン HTTP リクエスト ヘッダーのセットです。この情報のサーバー側を活用することで、デバイスやネットワークの状態に基づいて、コンテンツの配信方法を変更できます。これにより インクルーシブな ユーザーエクスペリエンスを実現できます
コンテンツ ネゴシエーションの重要性
クライアント ヒントは、コンテンツ ネゴシエーションの別の方法です。つまり、ブラウザのリクエスト ヘッダーに基づいてコンテンツ レスポンスを変更します。
コンテンツ ネゴシエーションの一例として、Accept
リクエスト ヘッダーがあります。ブラウザが認識するコンテンツ タイプ、およびサーバーがレスポンスのネゴシエートに使用できるコンテンツの種類を記述します。画像リクエストの場合、Chrome の Accept
ヘッダーの内容は次のようになります。
Accept: image/webp,image/apng,image/*,*/*;q=0.8
すべてのブラウザは JPEG、PNG、GIF などの画像形式をサポートしていますが、この場合、Accept はブラウザが WebP と APNG もサポートしていることを示しています。この情報を使用して、各ブラウザに最適な画像タイプをネゴシエートできます。
<?php
// Check Accept for an "image/webp" substring.
$webp = stristr($_SERVER["HTTP_ACCEPT"], "image/webp") !== false ? true : false;
// Set the image URL based on the browser's WebP support status.
$imageFile = $webp ? "whats-up.webp" : "whats-up.jpg";
?>
<img src="<?php echo($imageFile); ?>" alt="I'm an image!">
Accept
と同様に、Client Hints はコンテンツを交渉するためのもう 1 つの手段ですが、デバイスの機能とネットワーク状態のコンテキストにおけるものです。Client Hints を使用すると、ネットワーク状況が悪いユーザーに重要性の低いリソースを提供するかどうかなど、ユーザー個人のエクスペリエンスに基づいてサーバー側のパフォーマンスに関する決定を行うことができます。このガイドでは、利用可能なすべてのヒントと、それを使用してより快適なコンテンツ配信を実現する方法について説明します。
オプトイン
Accept
ヘッダーとは異なり、Client Hints は魔法のように表示されるわけではありません(ただし、Save-Data
については後で説明します)。リクエスト ヘッダーを最小限に抑えるため、ユーザーがリソースをリクエストしたときに Accept-CH
ヘッダーを送信することで、どのクライアント ヒントを受け取るかを選択する必要があります。
Accept-CH: Viewport-Width, Downlink
Accept-CH
の値は、サイトが後続のリソース リクエストの結果を決定するために使用する、リクエストされたヒントのカンマ区切りのリストです。クライアントがこのヘッダーを読み取ると、「このサイトが Viewport-Width
および Downlink
のクライアント ヒントを要求している」というメッセージが表示されます。具体的なヒント自体は気にする必要はありません。これについては後ほど説明します。
これらのオプトイン ヘッダーは任意のバックエンド言語で設定できます。たとえば、PHP の header
関数を使用できます。<meta>
タグの http-equiv
属性を使用して、これらのオプトイン ヘッダーを設定することもできます。
<meta http-equiv="Accept-CH" content="Viewport-Width, Downlink" />
すべての Client Hints があります。
クライアント ヒントでは、ユーザーがサイトへのアクセスに使用しているデバイスとネットワークのどちらかについて記述します。利用可能なすべてのヒントを簡単に説明します
デバイスヒント
一部のクライアント ヒントは、ユーザーのデバイスの特性(通常は画面の特性)を説明するものです。一部の指標はユーザーの画面に最適なメディア リソースを選択するのに役立ちますが、すべてがメディア中心であるとは限りません。
このリストの説明に入る前に、画面とメディア解像度を表す主な用語をいくつか確認しておくと役立ちます。
固有のサイズ: メディア リソースの実際のサイズ。たとえば、Photoshop で画像を開いた場合、画像サイズ ダイアログに表示されるサイズは固有のサイズを表します。
密度補正後の固有のサイズ: ピクセル密度に補正した後のメディア リソースの寸法。画像の固有のサイズをデバイス ピクセル比で割って算出されます。たとえば、次のマークアップがあるとします。
<img
src="whats-up-1x.png"
srcset="whats-up-2x.png 2x, whats-up-1x.png 1x"
alt="I'm that image you wanted."
/>
この場合、1x
画像の固有のサイズが 320x240 で、2x
画像の固有のサイズが 640x480 であるとします。画面デバイスのピクセル比が 2 のデバイス(Retina 画面など)にインストールされたクライアントによってこのマークアップが解析されると、2x
画像がリクエストされます。2x
画像の密度補正後の組み込みサイズは 320x240 です。640x480 を 2 で割ると 320x240 になるためです。
外部サイズ: CSS やその他のレイアウト要素(width
属性や height
属性など)が適用された後のメディア リソースのサイズ。たとえば、密度補正された固有のサイズ 320x240 の画像を読み込む <img>
要素があり、さらに CSS の width
プロパティと height
プロパティも設定されていて、それぞれに 256px
と 192px
の値が適用されているとします。この例では、その <img>
要素の外部サイズは 256x192 になります。
いくつかの用語を取り上げながら、利用可能なデバイス固有のクライアント ヒントのリストを見てみましょう。
ビューポートの幅
Viewport-Width
は、ユーザーのビューポートの幅(CSS ピクセル)です。
Viewport-Width: 320
このヒントを他の画面固有のヒントと組み合わせて使用することで、特定の画面サイズ(アート ディレクション)に最適な画像の処理(切り抜きなど)を行ったり、現在の画面幅で不要なリソースを省略したりできます。
DPR
DPR
(デバイス ピクセル比の略)は、ユーザーの画面の物理ピクセルと CSS ピクセルの比率を報告します。
DPR: 2
このヒントは、(srcset
属性での x
記述子のように)画面のピクセル密度に対応する画像ソースを選択する場合に便利です。
幅
Width
ヒントは、sizes
属性を使用して <img>
タグまたは <source>
タグによって配信された画像リソースに対するリクエストに表示されます。sizes
は、リソースの外部サイズをブラウザに伝えます。Width
はその外部サイズを使用して、現在のレイアウトに最適な固有のサイズの画像をリクエストします。
たとえば、ユーザーが 320 CSS ピクセルのワイド スクリーンで DPR が 2 のページをリクエストしているとします。デバイスは、sizes
という属性値 85vw
を含む <img>
要素(すべての画面サイズでビューポート幅の 85%)を超えないようにする必要があります。Width
ヒントがオプトインされている場合、クライアントは <img>
の src
のリクエストとともにこの Width
ヒントをサーバーに送信します。
Width: 544
この場合、クライアントはリクエストされた画像の最適な固有の幅が、ビューポートの幅(272 ピクセル)に画面の DPR(2)、つまり 544 ピクセルを掛けた値の 85% であることをサーバーにヒントとしています。
このヒントは、密度補正後の画面の幅が考慮されるだけでなく、この重要な情報とレイアウト内の画像の外的サイズとの整合性も考慮されるため、特に効果的です。これにより、サーバーは画面とレイアウトの両方に最適な画像レスポンスをネゴシエートできます。
コンテンツ - DPR
すでに説明したとおり、画面にはデバイス ピクセル比がありますが、リソースにも独自のピクセル比があります。最も単純なリソース選択のユースケースでは、デバイスとリソース間のピクセル比を同じにできます。しかし、DPR
ヘッダーと Width
ヘッダーの両方が使用されている場合、リソースの外的サイズによって、この 2 つが異なるシナリオが発生する可能性があります。ここで Content-DPR
ヒントの出番となります。
他のクライアント ヒントとは異なり、Content-DPR
はサーバーが使用するリクエスト ヘッダーではなく、DPR
ヒントと Width
ヒントを使用してリソースを選択するときは常にレスポンス ヘッダー サーバーが送信する必要があります。Content-DPR
の値は次の式の結果になります。
Content-DPR
= [選択した画像リソースのサイズ] ÷ ([Width
] ÷ [DPR
])
Content-DPR
リクエスト ヘッダーが送信されると、ブラウザは画面のデバイス ピクセル比とレイアウトに合わせて、指定された画像を拡大縮小する方法を認識します。そうしないと、画像が適切に拡大 / 縮小されない可能性があります。
デバイスメモリ
厳密には Device Memory API の一部である Device-Memory
は、現在のデバイスのおおよそのメモリ量を GiB 単位で示します。
Device-Memory: 2
このヒントのユースケースとしては、メモリが限られているデバイスのブラウザに送信される JavaScript の量を減らすことが考えられます。JavaScript は、通常、ブラウザで最もリソースを大量に消費するコンテンツ タイプであるためです。または、デコード時のメモリ使用量が少ないため、低 DPR イメージを送信することもできます。
ネットワークのヒント
Network Information API は、ユーザーのネットワーク接続のパフォーマンスを説明する別のカテゴリのクライアント ヒントを提供します。私の意見では、これらは最も有用なヒントのセットです。これにより、低速の接続でクライアントにリソースを配信する方法を変更することで、ユーザーに合わせたエクスペリエンスを実現できます。
RTT
RTT
ヒントは、アプリケーション レイヤのおおよそのラウンドトリップ時間(ミリ秒単位)を提供します。RTT
ヒントには、トランスポート レイヤ RTT とは異なり、サーバー処理時間が含まれます。
RTT: 125
読み込みパフォーマンスでレイテンシが果たす役割のために、このヒントは役に立ちます。RTT
ヒントを使用すると、ネットワークの応答性に基づいて決定を下すことができ、一部のリクエストを省略するなどして、エクスペリエンス全体の配信を高速化できます。
ダウンリンク
レイテンシは読み込みパフォーマンスにおいて重要ですが、帯域幅も影響を及ぼします。Downlink
ヒントはメガビット/秒(Mbps)で表され、ユーザーの接続のおおよそのダウンストリーム速度を示します。
Downlink: 2.5
Downlink
を RTT
と組み合わせて使用すると、ネットワーク接続の品質に基づいてユーザーへのコンテンツ配信方法を変更できます。
エクアドル時間(ECT)
ECT
ヒントは、有効な接続タイプを表します。この値は、接続タイプの列挙リストのいずれかです。各タイプは、RTT
と Downlink
の両方の値で指定された範囲内の接続を表します。
このヘッダーでは実際の接続タイプが何であるかは説明されません。たとえば、ゲートウェイが基地局か Wi-Fi アクセス ポイントかは報告されません。現在の接続のレイテンシと帯域幅を分析し、最も近いネットワーク プロファイルを決定します。たとえば、Wi-Fi 経由で低速なネットワークに接続する場合、ECT
には有効な接続の概算値である 2g
の値が入力されることがあります。
ECT: 2g
ECT
の有効な値は 4g
、3g
、2g
、slow-2g
です。このヒントは、接続品質を評価するための出発点として使用し、その後 RTT
ヒントと Downlink
ヒントを使用して絞り込むことができます。
データの保存
Save-Data
は、ページから送信されるデータの量を減らすというユーザーの好みを示すものであるため、ネットワーク状態を示すヒントではありません。
Save-Data
は、他のネットワーク ヒントと同様に使用できるため、ネットワーク ヒントとして分類することをおすすめします。また、高レイテンシ/低帯域幅の環境でもユーザーがこの機能を有効にする可能性があります。このヒントが存在する場合は、常に次のように表示されます。
Save-Data: on
Google では、Save-Data
でできることを紹介しました。パフォーマンスに多大な影響を及ぼす可能性があります。これはユーザーが送信するコンテンツの量を
減らすよう指示していることを示すシグナルですそのシグナルに耳を傾けて行動を起こせば、ユーザーはそれを高く評価します。
まとめ
クライアント ヒントで何を行うかはユーザー次第です。多くの情報を提供しているため 多くの選択肢がありますアイデアを得るために、クライアント ヒントが中西部の地方部に所在する架空の木材会社 Sconnie Timber で何ができるかを見てみましょう。遠隔地ではよくあることですが、ネットワーク接続は脆弱になる可能性があります。そこで役立つのが Client Hints のようなテクノロジーです
レスポンシブ画像
最もシンプルなレスポンシブ画像のユースケース以外は、複雑になる可能性があります。画面サイズや形式ごとに、同じ画像の複数のパターンとパターンがある場合はどうすればよいでしょうか。このマークアップは、非常にすぐに複雑になります。重要な概念(sizes
など)は忘れがちで、間違って理解されがちです。
<picture>
と srcset
は明らかに優れたツールですが、複雑なユースケースでは開発とメンテナンスに時間がかかることがあります。マークアップの生成は自動化できますが、<picture>
と srcset
が提供する機能は複雑であるため、その柔軟性を維持しながら自動化を行う必要があるため、その実現も困難です。
クライアント ヒントを使用すると、これを簡略化できます。クライアント ヒントを使用した画像レスポンスのネゴシエーションは次のようになります。
- ワークフローに応じて、まず
Viewport-Width
ヒントを確認して画像処理(アート向け画像)を選択します。 - 画像の解像度を選択するには、
Width
ヒントとDPR
ヒントを確認し、画像のレイアウト サイズと画面密度に適合するソースを選択します(srcset
におけるx
およびw
記述子の動作と同様)。 - ブラウザがサポートする最適なファイル形式を選択します(ほとんどのブラウザで
Accept
を利用できます)。
架空の木材会社のクライアントが関心を寄せたため、PHP で Client Hints を使用するシンプルなレスポンシブ画像選択ルーチンを開発しました。つまり、このマークアップをすべてのユーザーに送信する代わりに、次のように記述します。
<picture>
<source
srcset="
company-photo-256w.webp 256w,
company-photo-512w.webp 512w,
company-photo-768w.webp 768w,
company-photo-1024w.webp 1024w,
company-photo-1280w.webp 1280w
"
type="image/webp"
/>
<img
srcset="
company-photo-256w.jpg 256w,
company-photo-512w.jpg 512w,
company-photo-768w.jpg 768w,
company-photo-1024w.jpg 1024w,
company-photo-1280w.jpg 1280w
"
src="company-photo-256w.jpg"
sizes="(min-width: 560px) 251px, 88.43vw"
alt="The Sconnie Timber Staff!"
/>
</picture>
個々のブラウザのサポートに基づいて、次のように減らすことができました。
<img
src="/image/sizes:true/company-photo.jpg"
sizes="(min-width: 560px) 251px, 88.43vw"
alt="SAY CHEESY PICKLES."
/>
この例では、/image
URL は PHP スクリプトで、その後に mod_rewrite によって書き換えられたパラメータが続きます。画像のファイル名と追加のパラメータを受け取り、バックエンド スクリプトが指定された条件に最適な画像を選択できるようにします。
最初の質問は「でも、これは単にバックエンドで <picture>
と srcset
を再実装するだけではないでしょうか?」ということでしょう。
ある意味では必要ですが、重要な違いがあります。アプリケーションでクライアント ヒントを使用してメディア レスポンスを作成する場合、すべてではないにしても、ほとんどの作業は自動化がはるかに容易です。これには、ユーザーに代わってこれを行うサービス(CDN など)を含めることができます。一方、HTML ソリューションでは、あらゆるユースケースに対応するために新しいマークアップを記述する必要があります。もちろん、マークアップの生成は自動化できます。しかし、設計や要件が変わった場合は、後で自動化戦略を見直す必要がある可能性が高くなります。
クライアント ヒントを使用すると、可逆の高解像度の画像から開始できます。この画像は、画面とレイアウトの任意の組み合わせに最適なサイズに動的にサイズ変更できます。ブラウザで選択可能な画像候補の固定リストを列挙する必要がある srcset
とは異なり、このアプローチはより柔軟に使用できます。srcset
では、ブラウザに対して大まかなバリアント セット(256w
、512w
、768w
、1024w
など)を提供しなければなりませんが、Client-Hints に基づくソリューションは、大量のマークアップを必要とせずに、あらゆる幅に対応できます。
もちろん、画像選択ロジックを自分で記述する必要はありません。Cloudinary は、w_auto
パラメータを使用するときに、Client Hints を使用して画像レスポンスを作成します。クライアント ヒントをサポートするブラウザを使用すると、中央値でダウンロードされるバイト数が 42% 減少することが確認されています。
ご注意ください。PC 版 Chrome 67 の変更により、クロスオリジン クライアント ヒントのサポートが終了しました。幸いなことに、これらの制限はモバイル版 Chrome に影響することはなく、機能ポリシーの作業が完了すると、すべてのプラットフォームで完全に解除されます。
低速なネットワークでユーザーをサポートする
アダプティブ パフォーマンスとは、Client Hints で提供される情報、特にユーザーのネットワーク接続の現在の状態に関する情報に基づいて、リソースの配信方法を調整できるという考え方です。
Sconnie Timber のサイトでは、Save-Data
、ECT
、RTT
、Downlink
の各ヘッダーをバックエンド コードで調査し、ネットワークが遅いときの負荷を軽減する措置を講じています。これを行うと、ネットワーク品質スコアが生成されます。このスコアを使用して、ユーザー エクスペリエンスを向上させるために介入する必要があるかどうかを判断します。このネットワーク スコアは 0
~1
の範囲内です。ここで、0
はネットワーク品質の最悪で、1
は最高です。
最初に、Save-Data
が存在するかどうかを確認します。有効の場合、スコアは 0
に設定されます。これは、ユーザーがエクスペリエンスをより軽く高速にするために必要なことをすべて行おうとしていると想定しているためです。
ただし、Save-Data
が存在しない場合は、ECT
、RTT
、Downlink
の各ヒントの値を重み付けして、ネットワーク接続の品質を表すスコアを計算します。ネットワーク スコア生成のソースコードは GitHub で入手できます。ここでのポイントは、ネットワーク関連のヒントをなんらかの形で使用することで、低速のネットワークを使用するユーザーのエクスペリエンスを改善できるということです。
サイトがクライアント ヒントが提供する情報に適応していれば、「オール オア ナッシング」アプローチを採用する必要はありません。送信するリソースをインテリジェントに決定できますレスポンシブ画像選択ロジックを変更して、特定のディスプレイで低画質の画像を送信し、ネットワークの品質が低い場合に読み込みパフォーマンスを高速化できます。
この例では、低速なネットワークでのサイトのパフォーマンス向上に関して、Client Hints が与える影響を確認できます。以下は、クライアント ヒントに適応しない低速なネットワーク上のサイトの WebPagetest ウォーターフォールです。
同じ低速接続で同じサイトのウォーターフォールが動作するようになりました。ただし今回は、Client Hints を使用して、重要性の低いページリソースを除外します。
クライアント ヒントにより、ページの読み込み時間が 45 秒以上からその 10 分の 1 未満に短縮されました。このシナリオでの Client Hints のメリットは強調できませんが、低速のネットワークよりも重要な情報を求めるユーザーにとっては、大きな利点となります。
さらに、クライアント ヒントをサポートしていないブラウザのエクスペリエンスを損なうことなく、クライアント ヒントを使用できます。たとえば、ECT
ヒントの値を使用してリソース配信を調整しながら、サポートしていないブラウザにも完全なエクスペリエンスを提供する場合は、次のようにフォールバックをデフォルト値に設定できます。
// Set the ECT value to "4g" by default.
$ect = isset($_SERVER["HTTP_ECT"]) ? $_SERVER["HTTP_ECT"] : "4g";
ここで、"4g"
は、ECT
ヘッダーに記述されている最高品質のネットワーク接続を表します。$ect
を "4g"
に初期化しても、Client Hints をサポートしていないブラウザには影響しません。FTW にオプトイン
キャッシュに注意してください。
HTTP ヘッダーに基づいてレスポンスを変更するときは、そのリソースの今後のフェッチがキャッシュでどのように処理されるかに注意する必要があります。ここでは、Vary
ヘッダーが不可欠です。このヘッダーは、キャッシュ エントリに、渡されたリクエスト ヘッダーの値を保持します。簡単に言うと、特定の HTTP リクエスト ヘッダーに基づいてレスポンスを変更する場合は、ほとんどの場合、そのヘッダーを次のように Vary
に含める必要があります。
Vary: DPR, Width
ただし、これには大きな注意点があります。頻繁に変更されるヘッダー(Cookie
など)で、キャッシュに保存可能なレスポンスを Vary
することはおすすめしません。これらのリソースが実質的にキャッシュできなくなるからです。RTT
や Downlink
などの Client Hints ヘッダーは接続要因であり、頻繁に変更される可能性があるため、このことを知っておくと、Vary
を使用しないようにすることをおすすめします。これらのヘッダーのレスポンスを変更する場合は、ECT
ヘッダーのみをキー入力することを検討してください。これにより、キャッシュミスを最小限に抑えられます。
もちろん、これは最初にレスポンスをキャッシュに保存する場合にのみ適用されます。たとえば、コンテンツが動的な場合、HTML アセットはキャッシュに保存しません。これは、繰り返しアクセスするとユーザー エクスペリエンスを損なう可能性があるためです。このような場合は、Vary
を気にすることなく、必要に応じてレスポンスを自由に修正してください。
Service Worker での Client Hints
コンテンツ ネゴシエーションはもはやサーバーだけのものではありません。Service Worker はクライアントとサーバー間のプロキシとして機能するため、JavaScript を介してリソースを配信する方法を制御できます。これには Client Hints も含まれます。Service Worker の fetch
イベントで、次のように event
オブジェクトの request.headers.get
メソッドを使用して、リソースのリクエスト ヘッダーを読み取ることができます。
self.addEventListener('fetch', (event) => {
let dpr = event.request.headers.get('DPR');
let viewportWidth = event.request.headers.get('Viewport-Width');
let width = event.request.headers.get('Width');
event.respondWith(
(async function () {
// Do what you will with these hints!
})(),
);
});
オプトインしたすべての Client Hints ヘッダーは、この方法で読み取ることができます。ただし、こうした情報を入手する方法は他にもあります。ネットワーク固有のヒントは、navigator
オブジェクトの同等の JavaScript プロパティで読み取ることができます。
クライアント ヒント | 対応する JS |
---|---|
「ECT」 | `navigator.connection.effectiveType` |
RTT | 「navigator.connection.rtt」 |
「データの保存」 | `navigator.connection.saveData` |
「ダウンリンク」 | 「navigator.connection.downlink」 |
「デバイス - メモリ」 | 「navigator.deviceMemory」 |
これらの API は、in
演算子による機能チェックが必要な場所では利用できないためです。
if ('connection' in navigator) {
// Work with netinfo API properties in JavaScript!
}
ここからは、サーバーで使用するのと同様のロジックを使用できますが、クライアント ヒントとコンテンツをネゴシエートするためにサーバーは必要ありません。ユーザーがオフラインのときにコンテンツを提供しなければならない追加機能があるため、サービス ワーカーだけでも、より高速で復元力のあるエクスペリエンスを実現できます。
まとめ
Client Hints を使用すると、ユーザーのエクスペリエンスを完全に漸進的に高速化できます。特に複雑なユースケースでは、<picture>
や srcset
を使用するよりも簡単にレスポンシブ画像を提供できる方法で、ユーザーのデバイス機能に基づいてメディアを配信できます。これにより、開発側の時間と労力を削減できるだけでなく、リソース(特に画像)を最適化し、 よりもユーザーの画面をより細かくターゲットにすることができます。
何よりも重要なのは、Google が送信する内容や送信方法を変更することで、不安定なネットワーク接続を突き止め、ユーザーのギャップを埋めることができることです。これは、脆弱なネットワーク上のユーザーがサイトにアクセスしやすくするうえで非常に効果的です。Service Worker と組み合わせることで、オフラインでも利用できる非常に高速なサイトを作成できます。
Client Hints は Chrome と Chromium ベースのブラウザでのみ利用可能ですが、サポートしていないブラウザには支障をきたさないような方法で使用することができます。Client Hints を使用して、すべてのユーザーのデバイス機能とユーザーが接続先のネットワークを認識し、真にインクルーシブで調整可能なエクスペリエンスを実現することを検討してください。他のブラウザ ベンダーもその価値を認識し、導入の意思を示すでしょう。
リソース
- Client Hints を使用した自動レスポンシブ画像
- Client Hints とレスポンシブ画像 - Chrome 67 での変更点
- (クライアント)ヒントを使用する (スライド)
Save-Data
で高速かつ軽量のアプリケーションを配信する
この記事に関する貴重なフィードバックと編集をいただいた Ilya Grigorik、Eric Portis、Jeff Posnick、Yoav Weiss、Estelle Weyl に感謝します。