使用节省流量模式快速轻巧地交付应用

Chrome、Opera 和 Yandex 浏览器中提供的 Save-Data 客户端提示请求标头,让开发者能够为在其浏览器中选择启用节省流量模式的用户提供更轻巧、更快速的应用。

对轻量级页面的需求

Weblight stats

所有人都认同,更快、更轻的网页能够提供更令人满意的用户体验,有助于更好地理解和记住内容,并能提高转化率和收入。Google 研究表明,“…经过优化的页面加载速度比原始页面快四倍,使用的字节数减少 80%。由于这些页面的加载速度如此之快,我们还看到这些页面的流量增加了 50%。”

而且,虽然 2G 连接的数量终于在下降,但在 2015 年,2G 仍然是占主导地位的网络技术。3G 和 4G 网络的普及率和可用性正在迅速增长,但相关的拥有成本和网络限制对于数亿用户来说仍然是一个重要因素。

这些都是支持页面优化的有力论据。

还有其他改进网站速度的方法,无需开发人员直接参与,例如代理浏览器和转码服务。尽管此类服务非常流行,但它们也存在明显的缺点 - 简单的(有时是不可接受的)图像和文本压缩、无法处理安全 (HTTPS) 页面、仅优化通过搜索结果访问的页面等等。这些服务非常流行本身就表明,Web 开发人员没有正确地满足用户对快速轻巧的应用和页面的高需求。但是,实现这一目标是一条复杂且有时困难的道路。

Save-Data 请求标头

一种相当直接的技术是借助浏览器,使用 Save-Data 请求标头。通过识别此标头,网页可以为受成本和性能约束的用户自定义并交付优化的用户体验。

受支持的浏览器(如下)允许用户启用 *节省流量模式,从而允许浏览器应用一组优化措施,以减少呈现页面所需的数据量。当此功能公开或通告时,浏览器可能会请求较低分辨率的图像、延迟加载某些资源,或者通过应用其他特定于内容的优化(例如图像和文本资源压缩)的服务路由请求。

浏览器支持

  • Chrome 49+ 在用户启用移动设备上的“Data Saver”(数据保护程序)选项或桌面浏览器上的“Data Saver”(数据保护程序)扩展程序时,会通告 Save-Data
  • Opera 35+ 在用户在桌面设备上启用“Opera Turbo”模式,或在 Android 浏览器上启用“Data savings”(节省流量)选项时,会通告 Save-Data
  • Yandex 16.2+ 在桌面设备或 移动浏览器上启用 Turbo 模式时,会通告 Save-Data

检测 Save-Data 设置

要确定何时向用户提供“轻量”体验,您的应用可以检查 Save-Data 客户端提示请求标头。此请求标头指示客户端由于高传输成本、连接速度慢或其他原因而希望减少数据使用量。

当用户在其浏览器中启用节省流量模式时,浏览器会将 Save-Data 请求标头附加到所有传出请求(HTTP 和 HTTPS)。截至撰写本文时,浏览器仅在标头中通告一个 *on- 令牌 (Save-Data: on),但这将来可能会扩展以指示其他用户偏好。

此外,可以使用 JavaScript 检测 Save-Data 是否已开启

if ('connection' in navigator) {
  if (navigator.connection.saveData === true) {
    // Implement data saving operations here.
  }
}

检查 navigator 对象中是否存在 connection 对象至关重要,因为它表示网络信息 API,该 API 仅在 Chrome、Android 版 Chrome 和 Samsung Internet 浏览器中实现。从那里,您只需检查 navigator.connection.saveData 是否等于 true,您就可以在该条件下实现任何节省流量的操作。

The
Save-Data header revealed in Chrome's Developer Tools pictured along with the
Data Saver extension.
在桌面版 Chrome 中启用 Data Saver 扩展程序。

如果您的应用使用 Service Worker,它可以检查请求标头并应用相关逻辑来优化体验。或者,服务器可以在 Save-Data 请求标头中查找通告的偏好设置,并返回替代响应 - 不同的标记、更小的图像和视频等等。

实施技巧和最佳实践

  1. 使用 Save-Data 时,请提供一些支持它的 UI 设备,并允许用户轻松地在各种体验之间切换。例如
    • 通知用户支持 Save-Data 并鼓励他们使用它。
    • 允许用户使用适当的提示和直观的开/关按钮或复选框来识别和选择模式。
    • 当选择节省流量模式时,请声明并提供一种简单且明显的方式来禁用它,并在需要时恢复到完整体验。
  2. 请记住,轻量级应用并非低级应用。它们不会省略重要的功能或数据,只是更注重所涉及的成本和用户体验。例如
    • 照片库应用可能会提供较低分辨率的预览,或使用代码量较少的轮播机制。
    • 搜索应用可能会一次返回较少的结果,限制媒体密集型结果的数量,或减少呈现页面所需的依赖项数量。
    • 新闻导向的网站可能会显示较少的故事,省略不太受欢迎的类别,或提供较小的媒体预览。
  3. 提供服务器逻辑以检查 Save-Data 请求标头,并考虑在启用时提供替代的、更轻的页面响应 - 例如,减少所需的资源和依赖项数量,应用更积极的资源压缩等。
    • 如果您正在根据 Save-Data 标头提供替代响应,请记住将其添加到 Vary 列表中 - Vary: Save-Data - 以告知上游缓存,只有在存在 Save-Data 请求标头时,它们才应缓存并提供此版本。有关更多详细信息,请参阅与 缓存交互的最佳实践。
  4. 如果您使用 Service Worker,您的应用可以通过检查 Save-Data 请求标头的存在,或通过检查 navigator.connection.saveData 属性的值来检测节省流量选项何时启用。如果启用,请考虑是否可以重写请求以获取更少的字节,或使用已获取的响应。
  5. 考虑使用其他信号来增强 Save-Data,例如有关用户连接类型和技术的信息(请参阅 NetInfo API)。例如,即使未启用 Save-Data,您也可能希望向 2G 连接上的任何用户提供轻量级体验。相反,仅仅因为用户处于“快速”4G 连接上,并不意味着他们对节省流量不感兴趣 - 例如,在漫游时。此外,您可以结合 Device-Memory 客户端提示来增强 Save-Data 的存在,以便进一步适应内存有限的设备上的用户。用户设备内存也在 navigator.deviceMemory 客户端提示中通告。

配方

您可以通过 Save-Data 实现的目标仅受您的想象力限制。为了让您了解可能实现的目标,让我们来看几个用例。当您阅读本文时,您可能会想到自己的其他用例,因此请随时进行实验,看看有什么可能!

在服务器端代码中检查 Save-Data

虽然 Save-Data 状态是您可以通过 JavaScript 中的 navigator.connection.saveData 属性检测到的,但在服务器端检测它有时是更可取的。JavaScript 可能在某些情况下无法执行。此外,服务器端检测是在将其发送到客户端之前修改标记的唯一方法,这涉及到 Save-Data 最有益的一些用例。

在服务器端代码中检测 Save-Data 标头的特定语法取决于使用的语言,但对于任何应用后端,基本思路都应该是相同的。例如,在 PHP 中,请求标头存储在 $_SERVER 超全局数组中,索引以 HTTP_ 开头。这意味着您可以通过检查 $_SERVER["HTTP_SAVE_DATA"] 变量的存在和值来检测 Save-Data 标头,如下所示

// false by default.
$saveData = false;

// Check if the `Save-Data` header exists and is set to a value of "on".
if (isset($_SERVER["HTTP_SAVE_DATA"]) && strtolower($_SERVER["HTTP_SAVE_DATA"]) === "on") {
  // `Save-Data` detected!
  $saveData = true;
}

如果您在将任何标记发送到客户端之前放置此检查,则 $saveData 变量将包含 Save-Data 状态,并且可以在页面上的任何位置使用。通过说明的这种机制,让我们看几个示例,说明我们如何使用它来限制我们发送给用户的数据量。

为高分辨率屏幕提供低分辨率图像

Web 上图像的常见用例涉及提供两组图像:一组用于“标准”屏幕 (1x),另一组用于高分辨率屏幕(例如 Retina 显示屏),其大小是前者的两倍 (2x)。这类高分辨率屏幕不一定仅限于高端设备,并且正变得越来越普遍。在首选更轻量级应用体验的情况下,将较低分辨率 (1x) 图像发送到这些屏幕,而不是较大的 (2x) 变体可能是明智之举。要在存在 Save-Data 标头时实现此目的,我们只需修改发送到客户端的标记

if ($saveData === true) {
  // Send a low-resolution version of the image for clients specifying `Save-Data`.
  ?><img src="butterfly-1x.jpg" alt="A butterfly perched on a flower."><?php
}
else {
  // Send the usual assets for everyone else.
  ?><img src="butterfly-1x.jpg" srcset="butterfly-2x.jpg 2x, butterfly-1x.jpg 1x" alt="A butterfly perched on a flower."><?php
}

此用例完美地说明了只需付出极小的努力即可适应专门要求您发送更少数据的人员。如果您不喜欢在后端修改标记,您也可以通过使用 URL 重写模块(例如 Apache 的 mod_rewrite)来实现相同的结果。有一些关于如何通过相对较少的配置实现此目的的示例

您还可以通过简单地向 <html> 元素添加类来将此概念扩展到 CSS background-image 属性

<html class="<?php if ($saveData === true): ?>save-data<?php endif; ?>">

从这里,您可以在 CSS 中定位 <html> 元素上的 save-data 类,以更改图像的交付方式。您可以将低分辨率背景图像发送到高分辨率屏幕,如上面的 HTML 示例所示,或完全省略某些资源。

省略非必要的图像

Web 上的一些图像内容只是非必要的。虽然此类图像可以作为内容的良好补充,但对于那些试图尽可能节省流量套餐的人来说,它们可能不是理想的选择。在 Save-Data 最简单的用例中,我们可以使用前面介绍的 PHP 检测代码,并完全省略非必要的图像标记

<p>This paragraph is essential content. The image below may be humorous, but it's not critical to the content.</p>
<?php
if ($saveData === false) {
  // Only send this image if `Save-Data` hasn't been detected.
  ?><img src="meme.jpg" alt="One does not simply consume data."><?php
}

正如您在下图中看到的那样,此技术肯定会产生显著的效果

A comparison of non-critical imagery
being loaded when Save-Data is absent, versus that same imagery being omitted
when Save-Data is present.
比较了在没有 Save-Data 时加载非关键图像,以及在存在 Save-Data 时省略相同图像的情况。

当然,省略图像并不是唯一的可能性。您还可以根据 Save-Data 操作来放弃发送其他非关键资源,例如某些字体。

省略非必要的 Web 字体

虽然 Web 字体通常不会像图像那样占据给定页面总有效负载的大部分,但它们仍然非常流行。它们消耗的数据量也不可忽视。此外,浏览器获取和呈现字体的方式比您想象的要复杂得多,其中 FOITFOUT 和浏览器启发式等概念使呈现成为一项细致的操作。

因此,您可能想要为想要更精简用户体验的用户省略非必要的 Web 字体。使用 Save-Data 可以轻松地做到这一点。

例如,假设您已在您的网站上包含了 Fira Sans(来自 Google 字体)。Fira Sans 是一种出色的正文字体,但对于试图节省流量的用户来说,它可能不是那么重要。通过在存在 Save-Data 标头时向 <html> 元素添加 save-data 类,我们可以编写样式,首先调用非必要字体,然后在存在 Save-Data 标头时选择退出它

/* Opt into web fonts by default. */
p,
li {
  font-family: 'Fira Sans', 'Arial', sans-serif;
}

/* Opt out of web fonts if the `save-Data` class is present. */
.save-data p,
.save-data li {
  font-family: 'Arial', sans-serif;
}

使用这种方法,您可以将来自 Google 字体的 <link> 代码段保留在原位,因为浏览器会推测性地加载 CSS 资源(包括 Web 字体),方法是首先将样式应用于 DOM,然后检查是否有任何 HTML 元素调用样式表中的任何资源。如果有人碰巧启用了 Save-Data,Fira Sans 将永远不会加载,因为样式化的 DOM 永远不会调用它。Arial 将会介入替代。它不如 Fira Sans 好看,但对于那些试图扩展其流量套餐的用户来说,它可能是更可取的。

总结

Save-Data 标头没有太多细微之处;它要么开启,要么关闭,并且无论出于何种原因,应用都承担着根据其设置提供适当体验的责任。

例如,如果某些用户怀疑即使在连接状况不佳的情况下,应用内容或功能也会丢失,他们可能不允许节省流量模式。相反,有些用户可能会例行启用它,以尽可能保持页面小巧简洁,即使在连接状况良好的情况下也是如此。最好让您的应用假定用户想要完整且不受限制的体验,直到您通过明确的用户操作获得明确指示为止。

作为网站所有者和 Web 开发人员,让我们承担起管理我们内容的责任,以改善受数据和成本约束的用户的用户体验。

有关 Save-Data 和出色的实际示例的更多详细信息,请参阅 帮助您的用户 Save Data