借助 Chrome、Opera 和 Yandex 浏览器中提供的 Save-Data
客户端提示请求标头,开发者可以为在浏览器中选择启用流量节省模式的用户提供更精简、速度更快的应用。
使用轻量级页面的需求
每个人都认同,更快、更轻的网页可以提供更令人满意的用户体验,更好地理解和保留内容,并增加转化次数和收入。Google 研究表明,“...经过优化的网页的加载速度比原始网页快 4 倍,使用的字节数减少了 80%。由于这类网页的加载速度提高了许多,因此它们获得的流量也增加了 50%。”
此外,虽然 2G 连接数量最终呈下降趋势,但 2G 在 2015 年仍然是主要的网络技术。3G 和 4G 网络的普及和可用性快速增长,但相关的拥有成本和网络限制仍然是数亿用户的重要因素。
这些都是优化网页的重要依据。
有一些替代方法(例如代理浏览器和转码服务)无需开发者直接参与即可提高网站速度。虽然此类服务非常受欢迎,但它们也存在一些严重的缺点 - 图片和文本压缩简单(有时是不可接受的)、无法处理安全 (HTTPS) 网页、仅优化通过搜索结果访问的网页,等等。这些服务非常受欢迎,这本身就表明 Web 开发者没有妥善满足用户对速度较快的应用和页面的高需求。但实现这一目标是一个复杂且有时困难的道路。
Save-Data
请求标头
有一种相当简单的方法就是使用 Save-Data
请求标头让浏览器提供帮助。通过识别此标头,网页可以自定义并为受费用和性能限制的用户提供经过优化的用户体验。
受支持的浏览器(如下所示)允许用户启用 *流量节省模式,从而授予浏览器应用一组优化的权限,以减少呈现网页所需的数据量。当公开或通告此功能时,浏览器可能会请求分辨率较低的图片、延迟加载某些资源,或通过应用其他特定内容优化方案(如图片和文本资源压缩)的服务来路由请求。
浏览器支持
- 当用户在移动设备上启用“流量节省程序”选项或在桌面浏览器上启用“流量节省程序”扩展程序时,Chrome 49 及更高版本会公布
Save-Data
。 - 当用户在桌面设备上启用“Opera Turbo”模式或在 Android 浏览器上启用“省流量”选项时,Opera 35 及更高版本会通告
Save-Data
。 - 在桌面设备或移动浏览器上启用加速模式后,Yandex 16.2+ 会通告
Save-Data
。
检测 Save-Data
设置
为了确定何时为用户提供“轻度”体验,应用可以检查 Save-Data
客户端提示请求标头。此请求标头表明,由于高传输费用、连接速度慢或其他原因,客户端偏好减少流量消耗。
当用户在其浏览器中启用流量节省模式时,浏览器会将 Save-Data
请求标头附加到所有传出请求(HTTP 和 HTTPS)中。撰写本文时,浏览器仅在标头 (Save-Data: on
) 中通告一个 *on- 令牌,但将来可能会扩展该令牌,以指明其他用户偏好设置。
此外,还可以检测在 JavaScript 中是否已打开 Save-Data
:
if ('connection' in navigator) {
if (navigator.connection.saveData === true) {
// Implement data saving operations here.
}
}
检查 navigator
对象中是否存在 connection
对象至关重要,因为它表示 Network Information API,该 API 仅在 Chrome、Android 版 Chrome 和三星互联网浏览器中实现。因此,您只需检查 navigator.connection.saveData
是否等于 true
,并且您可以在该条件下实现任何数据保存操作。
如果您的应用使用 Service Worker,则可以检查请求标头并应用相关逻辑来优化体验。或者,服务器可以在 Save-Data
请求标头中查找通告的偏好设置,并返回备用响应(不同的标记、较小的图片和视频,等等)。
植入提示和最佳实践
- 使用
Save-Data
时,请提供一些支持它的界面设备,并允许用户轻松地切换体验。例如:- 通知用户
Save-Data
受支持,并鼓励他们使用。 - 允许用户通过适当的提示和直观的开启/关闭按钮或复选框识别和选择模式。
- 选择流量节省模式后,应发出通知并提供一种简单明确的方法来停用该模式,并根据需要还原为完整体验。
- 通知用户
- 请记住,轻量级应用不只是轻量级应用。他们不会遗漏重要的功能或数据,只是更清楚相关的费用和用户体验。例如:
- 图库应用可能会提供分辨率较低的预览,或使用代码较少的轮播机制。
- 搜索应用一次可能会返回较少的结果、限制包含大量媒体内容的结果数量,或减少呈现网页所需的依赖项数量。
- 面向新闻的网站可能会显示较少的报道、省略不太常见的类别或提供较小的媒体预览。
- 提供服务器逻辑以检查
Save-Data
请求标头,并考虑在启用后提供更精简的备用页面响应,例如减少所需的资源和依赖项的数量、采用更积极的资源压缩等。- 如果您根据
Save-Data
标头提供备用响应,请务必将其添加到 Vary 列表Vary: Save-Data
中,以告知上游缓存它们应仅在Save-Data
请求标头存在时缓存并提供此版本。如需了解详情,请参阅与缓存交互的最佳实践。
- 如果您根据
- 如果您使用 Service Worker,则您的应用可以通过检查是否存在
Save-Data
请求标头或检查navigator.connection.saveData
属性的值来检测何时启用了数据保存选项。如果启用,请考虑是可以通过重写请求来减少提取的字节数,还是使用已提取的响应。 - 考虑在
Save-Data
中增加其他信号,例如有关用户连接类型和技术的信息(请参阅 NetInfo API)。例如,即使Save-Data
未启用,您也可能需要为使用 2G 连接的任何用户提供轻量级体验。反之,仅仅因为用户使用的是“快速”4G 连接,并不意味着他们对节省流量(例如在漫游时)不感兴趣。此外,您还可以使用Device-Memory
客户端提示增强Save-Data
的存在,以进一步适应内存有限的设备上的用户。用户设备内存也会在navigator.deviceMemory
客户端提示中通告。
Recipes
您通过 Save-Data
能够实现的内容仅限于您可以想到的操作。为了让您了解可能实现的功能,我们来了解一下几个使用场景。在阅读本文时,您可能会想出自己的其他用例,因此请大胆尝试,看看能实现哪些效果!
正在检查服务器端代码中的 Save-Data
虽然您可以在 JavaScript 中通过 navigator.connection.saveData
属性检测 Save-Data
状态,但有时最好在服务器端检测该状态。JavaScript 在某些情况下可能无法执行。此外,服务器端检测是在标记发送到客户端之前修改标记的唯一方式,这涉及到 Save-Data
的一些最有益的用例。
在服务器端代码中检测 Save-Data
标头的具体语法取决于所使用的语言,但基本思路应当适用于所有应用后端。例如,在 PHP 中,请求标头存储在以 HTTP_
开头的索引处的 $_SERVER
超全局数组中。这意味着您可以通过检查 $_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
状态,并且可在网页上的任何位置使用。举例说明这种机制后,让我们通过几个示例来了解如何使用该机制限制向用户发送的数据量。
针对高分辨率屏幕提供低分辨率图片
网络上图片的常见用例包括以两组图片的形式提供图片:一张图片用于“标准”屏幕 (1x),另一张图片用于高分辨率屏幕(例如 2 倍屏幕)Retina 显示屏)。这类高分辨率屏幕并不一定仅限于高端设备,并且越来越常见。如果希望提供更轻量的应用体验,那么谨慎的做法是将分辨率较低的 (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
}
这个应用场景完美诠释了:有些人特别要求你减少发送的数据,所需的工作量少之又少。如果您不想修改后端的标记,也可以通过使用网址重写模块(例如 Apache 的 mod_rewrite
)来实现相同的效果。一些示例说明了如何通过相对较少的配置实现此目标。
您还可以向 <html>
元素添加一个类,从而将此概念扩展到 CSS background-image
属性:
<html class="<?php if ($saveData === true): ?>save-data<?php endif; ?>">
在这里,您可以在 CSS 中的 <html>
元素上定位 save-data
类,以更改图片的传送方式。您可以将低分辨率背景图片发送到高分辨率屏幕(如上面的 HTML 示例所示),也可以完全省略某些资源。
省略非必要的图像
网络上的某些图片内容根本不是必需内容。虽然除了内容之外,此类图像还很不错,但可能并不适合那些试图从按流量计费的流量套餐中压缩所有流量的用户。在 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
}
此方法当然具有显著的效果,如下图所示:
当然,省略图片并不是唯一的可能。您还可以对 Save-Data
执行操作,以免发送其他非关键资源(例如某些字体)。
省略不必要的网页字体
虽然网页字体在给定网页总载荷中所占的比例通常不如图片通常所占的比例,但它们仍然很受欢迎。它们也不会消耗大量数据。 此外,浏览器提取和渲染字体的方式比您想象的更复杂,因为 FOIT、FOUT 和浏览器启发式算法等概念使渲染操作变得非常精细。
您可能会想,对于那些想要精简用户体验的用户,您可能不想使用一些非必要的网页字体。Save-Data
使此操作变得很轻松。
例如,假设您在网站上添加了 Google Fonts 中的 Fira Sans。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 Fonts 的 <link>
代码段,因为浏览器会推测性加载 CSS 资源(包括网页字体),具体方法是先向 DOM 应用样式,然后检查是否有任何 HTML 元素调用了样式表中的任何资源。如果有人在启用 Save-Data
的情况下发生,Fira Sans 绝不会加载,因为已设定样式的 DOM 绝不会调用它。系统会改而使用 Crashlytics。它不像 Fira Sans 那么好,但对于那些尝试扩展流量套餐的用户来说,它可能更合适。
摘要
Save-Data
头文件没有太大的细微差别;它可能是开启或关闭,而无论出于何种原因,应用都要根据其设置提供适当的体验。
例如,如果某些用户怀疑应用内容或功能会丢失,即使连接状况不佳,也可能不允许使用流量节省模式。反过来,即使在连接状况良好的情况下,有些用户也可能会尽可能确保页面简洁明了。最好让应用假定用户想要获得全面且无限制的体验,除非您通过明确的用户操作以其他方式明确指示。
作为网站所有者和 Web 开发者,我们有责任管理我们的内容,为数据和费用受限的用户改善用户体验。
如需详细了解 Save-Data
和优秀的实践示例,请参阅帮助用户Save Data
。