利用客户端提示适应用户

开发什么都能快速加载的网站可能并非易事。大量 以及设备所连接的网络的质量 可能会使这项任务看起来很难。虽然我们可以 如何利用浏览器功能提高加载性能,我们怎么知道 用户设备的网络性能或网络质量 连接?解决之道是 提示

客户端提示是一组选择启用的 HTTP 请求标头 用户设备及其所连接网络的这些方面。修改者 因此改变了我们的实现方式 根据设备和/或网络条件显示内容。这有助于我们 打造更具包容性的用户体验。

一切都围绕内容协商

客户端提示是另一种内容协商方法,这意味着 基于浏览器请求标头的内容响应。

内容协商的一个例子是 Accept 请求标头。它描述了浏览器能识别的内容类型, 服务器可用来协商响应。对于图片请求,内容 的 Accept 标头为:

Accept: image/webp,image/apng,image/*,*/*;q=0.8

虽然所有浏览器都支持 JPEG、PNG 和 GIF 等图片格式,但接受 在这种情况下,浏览器也支持 WebPAPNG。利用这些信息,我们可以 协商每个浏览器的最佳图片类型:

<?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 一样,客户端提示是协商内容的另一种途径,但 设备功能和网络条件的背景。有了客户提示, 可以根据用户的个人情况做出服务器端性能决策 例如,决定是否应向服务器提供非关键资源 网络状况不佳的用户在本指南中,我们将介绍 还有一些可用提示,以及有助于提升内容传送效率的一些方法 提供便利

选择启用

Accept 标头不同,客户端提示不仅会神奇地出现(使用 Save-Data 除外)。为了确保 您需要选择接收哪些客户端提示 当用户请求发送 Accept-CH 标头时, 资源:

Accept-CH: Viewport-Width, Downlink

Accept-CH 的值是以英文逗号分隔的网站请求提示列表 用于确定后续资源请求的结果。当 客户读取此标头,系统被告知“此网站想要Viewport-WidthDownlink 个客户提示。”您无需担心具体提示本身。 我们稍后会解答这些问题。

您可以使用任何后端语言设置这些选择启用标头。例如,PHP 的 可以使用 header 函数。 您甚至可以使用http-equiv 属性 使用 <meta> 标记时:

<meta http-equiv="Accept-CH" content="Viewport-Width, Downlink" />

所有客户端提示!

客户端提示描述了以下两种内容之一:用户所使用的设备、使用以及 他们用来访问您网站的网络我们简单介绍一下 可用提示。

设备提示

一些客户端提示会描述用户设备的特征,通常为屏幕 特征。其中一些资源可以帮助您为客户选择最合适的媒体资源, 但并非所有屏幕都以媒体为中心。

在我们介绍此列表之前,了解一些关键术语,可能会对您有所帮助 描述屏幕和媒体分辨率:

固有尺寸:媒体资源的实际尺寸。例如,如果 当您在 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 和其他布局之后的尺寸 因素(例如 widthheight 属性)。让我们 假设您有一个 <img> 元素,用于加载已校正密度的图片 固有尺寸为 320x240,但它也具有 CSS widthheight 属性 分别应用了 256px192px 值。在此示例中 该 <img> 元素的外部尺寸将变为 256x192。

固有尺寸与
数据。显示一个大小为 320x240 像素的框,并带有“内部”标签
尺寸。其中包含一个大小为 256x192 像素的较小框,表示
已应用 CSS 的 HTML img 元素。此方框已标记为“外部”
尺寸。右侧是一个框,其中包含应用到该元素的
修改 img 元素的布局,使其外部尺寸
及其固有大小。
图 1.固有特征与固有特性对比图示 数据。在调整布局因素后,图片会获得其外在尺寸 。在本例中,应用width: 256px;的 CSS 规则 和 height: 192px; 转换一个固有大小的 320x240 图片 外部尺寸为 256x192 的广告素材。

了解了一些术语之后,我们来看一下设备专用列表 为您提供的客户端提示

视口宽度

Viewport-Width 是用户视口的宽度(以 CSS 像素为单位):

Viewport-Width: 320

此提示可与其他特定于屏幕的提示结合使用,以传达不同的 针对特定屏幕尺寸的最佳图片处理方式(即剪裁) (例如,艺术 方向), 或省略对当前屏幕宽度而言不必要的资源。

DPR

DPR(设备像素比)的缩写,用于报告物理像素与 CSS 的比率 像素:

DPR: 2

在选择与屏幕的 像素密度(类似于 srcset 中的 x 描述符) 属性)。

宽度

Width 提示出现在由 <img> 或 使用了 sizes<source> 个标记 属性sizes 用于告知浏览器资源的外部大小; Width 使用该外在尺寸来请求具有固有尺寸的图片 是当前布局的最佳选择。

例如,假设用户请求的网页宽度为 320 CSS 像素 DPR 为 2设备加载包含 <img> 元素的文档,该元素包含 sizes 属性值 85vw(即全部视口宽度的 85% 屏幕尺寸)。如果已选择接受 Width 提示,客户端将发送 此 Width 会通过请求 <img>src 来提示服务器:

Width: 544

在这种情况下,客户端会提示服务器, 所请求图片的宽度将为视口宽度的 85%(272 像素) 乘以屏幕的 DPR (2),即 544 像素。

这一提示尤为有力,因为它不仅考虑了 屏幕的密度校正宽度,但也与这一关键部分 以及图片在布局内的外在尺寸信息。如此一来, 服务器就有机会协商对这两者都最优的图片响应 屏幕和布局。

内容-DPR

虽然您已经知道屏幕具有设备像素比,但资源也 都有各自的像素比在最简单的资源选择用例中, 设备和资源之间的宽高比可以相同。但是!如果 DPRWidth 头文件,则资源的外部大小可以 会产生出现差异的场景。这就是 Content-DPR 提示的地方 。

与其他客户端提示不同,Content-DPR 不是供以下 API 使用的 request 标头 而是响应标头服务器必须发送响应DPRWidth 提示用于选择资源。Content-DPR 的值应 是以下等式的结果:

Content-DPR = [所选图片资源大小] / ([Width] / [DPR])

发送 Content-DPR 请求标头后,浏览器就会知道如何扩缩 屏幕的设备像素比和布局的指定图像。如果没有它, 图片可能无法正确缩放。

设备内存

从技术层面来讲,这是设备内存的组成部分 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

RTT 结合使用时,Downlink 在改变内容显示方式方面非常有用 根据网络连接质量向用户提供

厄瓜多尔时间

ECT 提示代表“Effective Connection Type”。其值是 连接类型的枚举列表,其中每个连接都描述了RTTDownlink 的指定范围内 值

此标头没有说明实际的连接类型是什么,具体如下: 它不会报告您的网关是手机基站还是 Wi-Fi 访问 。而是分析当前连接的延迟时间和带宽, 确定它最相似的网络配置文件。例如,如果您连接到 通过 Wi-Fi 连接到慢速网络,ECT 可能会填充值 2g, 该值是最接近有效连接的近似值:

ECT: 2g

ECT 的有效值包括 4g3g2gslow-2g。此提示可以是 用作评估连接质量的起点,随后 使用 RTTDownlink 提示进行优化。

保存数据

Save-Data 并不是描述网络状况的提示,而是用户 偏好设置,说明网页应发送较少的数据。

我更喜欢将 Save-Data 分类为网络提示,因为许多事情 这与其他网络提示类似。用户还可能会 可能在高延迟/低带宽环境中启用此功能。这个提示 始终显示如下:

Save-Data: on

在 Google,我们已经讨论了 Save-Data。 它对性能的影响可能非常深远。它是一种信号 真的会要求你少给他们发送一些东西!如果你认真倾听并采取相应行动 用户会喜欢它。

融会贯通

使用客户端提示执行的操作取决于您。因为它们提供 您有多种选择。为了让您产生灵感,让我们看看 客户提示对小康有何帮助 木材,一种虚构的木材 这家公司位于中西部农村地区。远程工作通常如此 区域, 因此网络连接变得很脆弱这时客户端等技术就会提示 能够为用户带来真正的改变

自适应图片

除了最简单的自适应图片用例之外,其他所有用例都可能会很复杂。如果你 同一图片针对不同屏幕采用多种处理方式和变体 尺寸和格式?该标记会变得非常复杂 快速。 人很容易犯错,也容易忘记或误解重要信息 概念(例如 sizes)。

虽然 <picture>srcset 不可否认很棒,但它们 为复杂的用例开发和维护耗时。我们可以实现自动化 但生成标记也很困难 <picture>srcset 提供的功能非常复杂,满足他们的自动化需求 保持其灵活性

客户端提示可以简化这一过程。与客户端协商图片响应 提示可能如下所示:

  1. 如果适用于您的工作流程,请先选择图片处理方式(即 艺术类图像)时,请查看 Viewport-Width 提示。
  2. 通过检查 Width 提示和 DPR 提示来选择图片分辨率,并且 选择适合图片的布局尺寸和屏幕密度的来源(类似 了解 xw 描述符在 srcset 中的工作原理)。
  3. 选择浏览器支持的最佳文件格式(Accept 可以帮助我们在大多数浏览器中完成相应操作)。

在我虚构的木材公司客户方面,我开发了一个 使用客户端提示的 PHP 中的自适应图片选择例程。这意味着 而不是将此标记发送给所有用户:

<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 网址是一个带参数的 PHP 脚本 改写者 mod_rewrite。它 它采用图片文件名和其他参数来帮助后端脚本 在指定条件下选择最佳图片。

我感觉“但这不只是重新实现了 <picture>srcset, ”是您的第一个问题。

从某种意义上说是的,但有一个重要的区别:当应用使用 客户提示撰写媒体响应时,大部分(如果不是全部)工作 其中可能包括可执行该操作的服务(例如 CDN) 。而使用 HTML 解决方案,则需要将新的标记写入 能够满足各种应用场景的需要当然,您可以自动生成标记。如果您的 但很有可能您就需要 并回顾您的自动化策略。

客户端提示让您可以使用无损的高分辨率图像开始, 然后可动态调整其大小,从而针对任意组合实现最佳效果 屏幕和布局与 srcset 不同,它要求您枚举固定的 可供浏览器选择的可能候选图片的列表,此方法 可能更加灵活虽然 srcset 会强制您为浏览器提供粗略的 (例如,256w512w768w1024w)- client-hints 赋能的解决方案可适应所有宽度,而无需大量标记。

当然,您无需自行编写图片选择逻辑。Cloudinary 使用 w_auto 时,使用客户端提示来创建图片响应 参数, 并观察到,使用浏览器时,中位数用户下载的字节数减少了 42% 辅助性客户端提示。

但要注意!桌面版 Chrome 67 中的一些变化不再支持 适用于跨域客户端 提示。 幸运的是,这些限制不会影响移动版 Chrome,并且 针对功能进行升级后,所有平台都会全面升级 Policy

为网速较慢的用户提供帮助

自适应性能的理念是,我们可以调整资源的分发方式, 根据客户端提示提供给我们的信息生成;具体来说就是 有关用户网络连接的当前状态的信息。

对于 Sconnie Timber 的网站,我们采取了一些措施来减轻 网络速度较慢,Save-DataECTRTTDownlink 标头使用 检查过哪些漏洞完成后,我们会生成一个网络质量报告, 得分,我们据此确定是否应干预,以获得更好的用户 体验。此网络得分介于 01 之间,其中 0 为最低 网络质量,1 是最佳。

最初,我们检查 Save-Data 是否存在。如果是,则得分将设置为 0,因为我们假设用户希望我们执行使 让应用变得更轻巧、更快速

不过,如果 Save-Data 不存在,我们会继续计算 ECT 的值, RTTDownlink 提示计算描述网络的得分 连接质量。网络得分生成来源 代码 可在 GitHub 上找到。结论是,如果我们在实验中使用与网络相关的提示, 一些时尚,我们可以为网速慢的用户提供更好的体验 。

与不使用客户端的网站进行比较
提示应适应慢速网络连接(左图),
(右)。
图 2:本地用户的“关于我们”页面 。基准体验包括网页字体和 JavaScript, 轮播和可折叠内容的行为以及内容图片。这些都是 我们可以在网络条件太慢时将其省略

当网站根据客户端提示提供的信息进行调整时,我们就不必采用 “一刀切”式的方法。我们可以智能地确定要 send。我们可以修改自适应图片选择逻辑, 以便在网络质量不佳时提高性能, 很差。

在此示例中,我们可以看到客户端提示对 改善网站在网速较慢时的性能。以下是一个 WebPagetest 无法根据客户端提示进行调整的网站广告瀑布流:

史康尼河的 WebPagetest 瀑布
木材网站在网速较慢时加载所有资源。
图 3:网站加载图片时占用大量资源, 脚本和字体。

现在,同一网站在慢速连接上呈现的 瀑布图, 之后,该网站会使用客户端提示排除非关键网页资源:

史康尼河的 WebPagetest 瀑布
使用客户端提示来决定不在某个位置加载非关键资源的木材网站
网络连接速度太慢
图 4:通过同一连接访问同一网站 只会排除“锦上添花”的资源, 正在加载。

客户端提示将网页加载时间从 45 秒以上缩短到不到 10%。在这种情况下,客户提示的优势 能够得到足够强调,对寻求关键信息的用户来说 通过慢速网络传输信息。

此外,您还可以使用客户端提示而不破坏游戏体验 。例如,如果我们要调整 遵循 ECT 提示的值,同时仍然提供完整的 则我们可以将回退到默认值 如下所示:

// Set the ECT value to "4g" by default.
$ect = isset($_SERVER["HTTP_ECT"]) ? $_SERVER["HTTP_ECT"] : "4g";

其中,"4g" 表示 ECT 标头中质量最高的网络连接 描述。如果我们将 $ect 初始化为 "4g",不支持客户端的浏览器就会停止响应 提示不会受到影响。选择加入 FTW!

小心缓存!

每当您根据 HTTP 标头更改响应时,都需要注意 缓存将如何处理以后对该资源的提取。Vary 标头为 在这里是不可或缺的,因为它将缓存条目缓存到请求标头的值 。简而言之,如果您根据指定的 HTTP 请求修改任何响应, 请求标头,您几乎应始终在 Vary 中包含该标头 如下所示:

Vary: DPR, Width

但有一点需要特别注意:切勿对可缓存内容执行 Vary 操作。 在频繁更改的标题(如 Cookie)上发送响应,因为这些 导致资源实际上无法缓存。知道这一点后,您可能希望 对 RTTDownlink 等客户端提示标头执行 Vary 操作,因为这些是 可能频繁变化的连接因素。如果您想修改 则可以考虑仅输入 ECT 标头, 最大限度地减少缓存未命中。

当然,这仅适用于您首先缓存响应的情况。 例如,如果 HTML 资源的内容是动态的,您就不需要缓存这些资源,因为 可能会对重复访问的用户体验造成不利影响。遇到这类情况时,请 您可随时根据需要修改此类回答, Vary

Service Worker 中的客户端提示

内容协商已不再局限于服务器!由于 Service Worker 作为客户端和服务器之间的代理,您可以控制 通过 JavaScript 投放。这包括客户端提示。在 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!
    })(),
  );
});

您选择的任何客户端提示标头都可以以这种方式进行读取。尽管如此, 这并不是获取其中部分信息的唯一途径。针对特定广告网络的提示 可在 navigator 对象中的以下等效 JavaScript 属性中读取:

客户端提示 JS 等效项
ECT `navigator.connection.effectiveType`
RTT `navigator.connection.rtt`
“保存数据” `navigator.connection.saveData`
`Downlink` `navigator.connection.downlink`
“设备内存” `navigator.deviceMemory`
适用于文件类型的 Imagemin 插件。

由于这些 API 并不适用于所有位置,因此您需要向 in 运算符

if ('connection' in navigator) {
  // Work with netinfo API properties in JavaScript!
}

在这里,您可以使用与在服务器上使用的逻辑类似的逻辑,但以下情况除外: 您不需要服务器来与客户端提示协商内容。服务 单靠劳动者就能够打造更快、更有弹性的体验, 增添了在用户离线时提供内容的功能。

总结

有了客户端提示,我们就能够为所在区域的用户提供更快的体验 完全渐进式的方式我们可以根据用户的设备投放媒体 因此,您可以更轻松地提供自适应图片, 适用于 <picture>srcset,尤其是对于复杂的用例。这使我们能够 这不仅可以减少开发方面的时间和精力,还可以优化 使资源(尤其是图片)能够定位到用户所用屏幕 进行得比 和 srcset 做得更细。

或许更重要的是,我们可以探出连接不良的网络连接状况, 通过修改我们发送的内容及其发送方式来减少用户的差距。这可以 在帮助脆弱网络用户更轻松地访问网站方面发挥着长远的作用。 通过与 Service Worker 结合使用,我们可以打造出 可离线使用

客户端提示仅适用于 Chrome 和基于 Chromium 那么您就可以以不妨碍浏览的方式使用它们 。不妨考虑使用客户端提示 提供包容且适应性强的体验,能够感知每位用户的设备 功能及其所连接的网络。希望其他浏览器供应商 会看到它们的价值,并表现出实施的意愿。

资源

感谢 Ilya GrigorikEric PortisJeff PosnickYoav WeissEstelle Weyl, 请针对本文提供宝贵的反馈和修改。