Web 上的响应式图片:如何使用 srcset 构建






4.80/5 (13投票s)
响应式网站的一个重要组成部分是响应式图片。在本文中,我们将更深入地了解 Web 上的响应式图片,并学习如何构建它们。
在这个互联互通的世界里,人们拥有各种各样的设备,确保您的网站在所有设备上都能无缝运行,这已不再是可选项,而是必需项。您的网站视图将不再仅仅来自单一分辨率的设备,或单一的设备形态。为了满足所有这些设备,您的网站需要具有响应性。
如果您熟悉响应式网页设计 (RWD),您可能已经了解了响应式设计所带来的复杂性(以及 Bootstrap 如何解决了其中的许多问题!)。响应式网站的一个重要组成部分是响应式图片。在本文中,我们将更深入地了解 Web 上的响应式图片,并学习如何构建它们。
什么是响应式图片?
简单来说,响应式图片是指根据用户查看您网站所使用的设备,在网页上以最佳形式显示的图片。“最佳形式”可能意味着多种含义:
- 您希望根据用户的物理屏幕尺寸显示不同的图片资源。例如:您希望在 13.5 英寸的笔记本电脑和 5 英寸的手机(在最大化浏览器的情况下)上显示不同的图片资源。
- 您希望根据设备的屏幕分辨率(或设备像素比,即设备像素与 CSS 像素的比率)显示不同的图片。
- 如果您希望在浏览器支持的情况下显示特定格式的图片(例如 JPEG XR),那么您可能会这样做,因为该格式支持更高的压缩率。
响应式的构建块已包含在大多数现代浏览器中,包括 Microsoft Edge(从Windows Insider Build 10547 开始)。您可以在此处查看 srcset 等功能的 Web 平台状态。
如何启用响应式图片?
有多种方法可以启用图片的响应式行为。其中一种较旧的方法(不推荐)是使用简单的脚本,但这会导致一些问题。首先,如果脚本决定下载哪张图片,但脚本本身是在 HTML 中指定的图片下载之后加载的,那么您可能会下载两张图片。其次,如果您在 HTML 中没有指定任何图片,并且只想加载由脚本定义的图片,那么对于禁用了脚本的浏览器,您将完全看不到图片。
因此,我们需要一种更好的方法来处理响应式图片。幸运的是,我们有了!推荐的方法是使用
srcset
属性sizes
属性picture
元素
让我们深入了解一下。
srcset 属性
在探讨 srcset
的实际用法之前,让我们先理解一些术语。
设备像素比
设备像素比是每 CSS 像素的设备像素数。设备像素比受两个关键条件的影响:
1. 设备的像素密度(每英寸物理像素数)
高分辨率设备将具有更高的像素密度,因此,在相同的缩放级别下,与低分辨率设备相比,它将具有更高的设备像素比。例如:高端 Lumia 950 手机的分辨率将高于经济型 Lumia 630 手机,因此在相同的缩放级别下,它将具有更高的设备像素比。
2. 浏览器的缩放级别
对于同一设备,更高的缩放级别意味着每 CSS 像素的设备像素数更多,因此设备像素比更高。例如,考虑下图:
当您在浏览器中放大(Ctrl + 加号)时,您的 div 的 CSS 像素数量保持不变,但它占据的设备像素数量会增加。因此,每 CSS 像素的设备像素数量会更高。
当您希望根据设备像素比显示不同的图片(通常是同一图片的另一个资源)时,您将采用基本的 srcset
实现。
<img src="images/space-needle.jpg"
srcset="images/space-needle.jpg 1x, images/space-needle-2x.jpg 2x, images/space-needle-hd.jpg 3x">
srcset
属性中的 x
描述符用于定义设备像素比。因此,
- 对于设备像素比为 1,将使用图片 space-needle.jpg。
- 对于设备像素比为 2,将使用图片 space-needle-2x.jpg。
- 对于设备像素比为 3,将使用图片 space-needle-hd.jpg。
src
属性用作不支持 srcset
实现的浏览器的回退。
这效果很好。使用 x
描述符,您将始终在具有相似设备像素比的设备上获得相同的图片——即使这意味着您在具有相同设备像素比的 13.5 英寸笔记本电脑和 5 英寸手机上获得相同的图片。
现在假设我们希望在更大的或更小的视口上显示不同尺寸(高度、宽度)的图片。这就是 srcset
的 w
描述符和一个新属性——sizes
发挥作用的地方。
w
描述符:这描述了所引用的图片的宽度。请看这个例子:
<img src="images/space-needle.jpg"
srcset="images/space-needle.jpg 200w, images/space-needle-2x.jpg 400w, images/space-needle-hd.jpg 600w">
这表明第一张图片的宽度为 200px,第二张图片为 400px,第三张图片为 600px。此外,如果用户的屏幕宽度为 150 CSS 像素,则相当于以下 x
描述符:
<img src="images/space-needle.jpg"
srcset="images/space-needle.jpg 1.33x, images/space-needle-2x.jpg 2.67x, images/space-needle-hd.jpg 4x">
(请记住,设备像素比只是设备像素/CSS 像素的数量。)
sizes 属性
当您希望在不同屏幕尺寸上显示不同尺寸图片(不同高度、宽度)的实际实现,是通过将 sizes
属性与 srcset
属性的 w
描述符结合使用来完成的。让我们再次通过几个例子来学习。
示例 1
假设您希望图片以视口宽度的一半显示。您可以输入:
<img
src="images/space-needle.jpg" sizes="50vw"
srcset="images/space-needle.jpg 200w, images/space-needle-2x.jpg 400w, images/space-needle-hd.jpg 600w">
浏览器现在将根据浏览器宽度和设备像素比来决定下载哪张图片。例如:
如果浏览器宽度为 500 CSS 像素,图片将显示为 250px 宽(因为 50vw)。现在,这相当于指定:
srcset="images/space-needle.jpg 0.8x, images/space-needle-2x.jpg 1.6x, images/space-needle-hd.jpg 2.4x"
所以,对于 1.5x 显示,浏览器将下载 images/space-needle-2x.jpg,因为它提供了 1.6x 的设备像素比(这最适合 1.5x 显示)。
示例 2
当视口宽度大于 40em 时,您希望图片以视口宽度的一半显示,但在视口宽度小于或等于 40em 时,图片应占据整个宽度。这就是您将如何实现这一点:
<img src="images/space-needle.jpg" sizes=" (max-width: 40em) 100vw, 50vw"
srcset="images/space-needle.jpg 200w, images/space-needle-2x.jpg 400w, images/space-needle-hd.jpg 600w">
这非常类似于媒体查询。因此,对于宽度为 39em 的视口,(max-width: 40em)
为 true,这意味着 100vw,即图片与视口一样宽。如果视口是浏览器窗口,并且浏览器宽度为 500 CSS 像素,则图片将显示为 500px 宽。这相当于指定:
<img src="images/space-needle.jpg" sizes=" (max-width: 40em) 100vw, 50vw"
srcset="images/space-needle.jpg 0.4x, images/space-needle-2x.jpg 0.8x, images/space-needle-hd.jpg
1.2x">
与上面类似,浏览器将决定为特定显示选择哪张图片。
对于宽度为 41em 的视口,(max-width: 40em
) 为 false,这意味着 50vw,即图片是视口宽度的一半。
接下来我们将看到的元素是 picture
元素,但在那之前,我需要快速回顾一下 :)
用例 | 解决方案 |
我希望在所有设备上显示相同的图片,但我想在能够支持它的设备上以更高的分辨率显示它。图片的宽度和高度应保持不变。 | 制作同一张图片的多个资源(space-needle.jpg, space-needle-hd.jpg)。使用带有 x 描述符的 srcset 。 |
我希望与上述场景相同,但能够根据视口自定义图片的宽度和高度。 | 使用带有 w 描述符的 sizes 和 srcset (再次,制作同一张图片的多个资源)。 |
我担心如果我对较小的屏幕尺寸使用相同的图片,我的图片的主要主体可能会变得太小。我希望在不同的屏幕尺寸上显示不同的图片(更侧重于主要主体),但我仍然希望根据设备像素比显示同一图片的各个资源,并且我希望根据视口自定义图片的宽度和高度。 | ? |
“?”的解决方案是 picture
元素!
picture 元素
如上所述,当您希望显示不同的图片取决于图片的渲染大小时,将使用 picture
元素。picture
元素是一个容器,其中包含控制要下载的图片的元素。让我们看一个例子:
<picture> <source media = "(max-width: 20em)" srcset="images/small/space-needle.jpg 1x, images/small/space-needle-2x.jpg 2x, images/small/space-needle-hd.jpg 3x > <source media = "(max-width: 40em)" srcset="images/medium/space-needle.jpg 1x, images/medium/space-needle-2x.jpg 2x, images/medium/space-needle-hd.jpg 3x > <img src="space-needle.jpg" alt="Space Needle"> </picture>
选择第一个 media 属性的 media query 为 true 的 source 元素。
因此,如果视口的最大宽度为 20em,则根据设备像素比,从 images/small 目录中选择相应的图片源。一个 srcset
中的所有图片通常是同一张图片的多个资源。
picture
元素本身不显示任何内容。即使是 picture
元素内的 source 元素也没有自己的表示。source 元素必须包含 srcset
属性,并且可以具有 sizes
、media
和 type
属性。必须在 picture
中添加 img 元素。没有 img 元素,您将看不到任何图片。picture
元素内的所有 source 元素都只是为了向图片提供源。
您还可以根据浏览器支持的图片格式进行图片选择。当仅仅基于格式就能节省大量图片大小时,这一点尤其有用。例如,JPEG-XR 是一种高效的图片格式,通常比 JPG 的图片文件大小更小,它受 Microsoft Edge 和 IE9+ 支持。使用 source 元素中的 type 属性,您可以测试这种格式:
<picture>
<source media = "(max-width: 30em)" type="image/vnd.ms-photo" srcset="images/small/space-needle.jxr 1x, images/small/space-needle-2x.jxr 2x, images/small/space-needle-hd.jxr 3x >
<source media = "(max-width: 30em)" type="image/jpg" srcset="images/small/space-needle.jpg 1x, images/small/space-needle-2x.jpg 2x, images/small/space-needle-hd.jpg 3x >
<img src="space-needle.jpg" alt="Space Needle">
</picture>
使用时,media 属性和 type 属性都必须为 true,才能选择该 source 元素。如果浏览器无法理解任何格式,它将回退到 img。
整合所有内容
在了解了响应式图片的工作原理后,让我们来看一个结合了所有三种元素——srcset
、sizes
和 picture
——的完整示例。
<!DOCTYPE html>
<html>
<head>
<title> Responsive images are here! </title>
</head>
<body style="width:100%">
<picture>
<source media="(max-width: 700px)" sizes="(max-width: 500px) 50vw, 10vw"
srcset="stick-figure-narrow.png 138w, stick-figure-hd-narrow.png 138w">
<source media="(max-width: 1400px)" sizes="(max-width: 1000px) 100vw, 50vw"
srcset="stick-figure.png 416w, stick-figure-hd.png 416w">
<img src="stick-original.png" alt="Human">
</picture>
</body>
</html>
在此示例中,我们使用了包含多个 source 元素的 picture
。第一个在最大宽度为 700px 时被选中。如果选中它,sizes
属性将根据我们提到的宽度断点决定要显示的图片的大小。实现方式与我们在 sizes
属性中看到的完全相同。因此,如果最大宽度为 500px(宽度范围从 0px-500px),图片将占据视口的一半。图片源的选择是基于设备像素比的。但是,如果视口宽度大于 500px(但 <=700px,因为我们位于第一个 source 元素内),那么图片将只占据视口的 1/10。
类似地,第二个 source 元素在最大宽度为 1400px 时被选中(这意味着现在宽度范围从 701px 到 1400px)。sizes
属性确保当视口宽度范围从 701px 到 1000px 时,图片的宽度与视口宽度相同,而当视口宽度范围从 1001px 到 1400px 时,图片占据视口宽度的一半。为了验证所有情况,我只需调整浏览器大小并进行检查。在实际使用中,您的网站将通过不同的设备访问,那时您将看到响应式图片的实际用途。这是输出:
(请注意,此处设置的所有图片源和图片宽度都仅用于演示,正如您所见,我绘制了一些有趣的火柴人!)
视口宽度设置在 1001px 和 1400px 之间:图片宽度是视口宽度的一半(使用的图片源是 stick-figure.png)。
视口宽度设置在 701px 和 1000px 之间:图片宽度与视口宽度相同。(使用的图片源是 stick-figure.png)。
视口宽度设置在 501px 和 700px 之间:图片宽度是视口宽度的 1/10。(使用的图片源是 stick-figure-narrow.png)。
视口宽度设置在 0px 和 500px 之间:图片宽度是视口宽度的一半。(使用的图片源是 stick-figure-narrow.png)。
我们几乎完成了!
响应式图片为您——开发者——提供了在用户使用的多种设备上为您的用户提供最佳体验的选项。如果您还没有在您的网站上集成响应式图片,现在是时候了。
希望您喜欢阅读本文!如果您想进一步讨论,请在 Twitter 上与我联系!
更多 Web 开发实践
本文是 Microsoft 技术布道师和工程师关于实际 JavaScript 学习、开源项目和互操作性最佳实践的网络开发系列的一部分,其中包括 Microsoft Edge 浏览器和新的 EdgeHTML 渲染引擎。
我们鼓励您使用 Windows 10 的默认浏览器 Microsoft Edge,在各种浏览器和设备上进行测试,并在 dev.microsoftedge.com 上使用免费工具。
- 扫描您的网站是否存在过时库、布局问题和可访问性问题
- 下载适用于 Mac、Linux 和 Windows 的免费虚拟机
- 查看包括 Microsoft Edge 路线图在内的各浏览器 Web 平台状态
- 在您自己的设备上远程测试 Microsoft Edge
我们工程师和布道者的更深入的学习
- GitHub 上的编程实验室:跨浏览器测试和最佳实践
- Microsoft Edge Web Summit 2015(来自我们的工程团队和 JS 社区)
- Woah, I can test Edge & IE on a Mac & Linux!(来自 Rey Bango)
- Advancing JavaScript without Breaking the Web(来自 Christian Heilmann)
- The Edge Rendering Engine that makes the Web just work(来自 Jacob Rossi)
- Unleash 3D rendering with WebGL(来自 David Catuhe)
- Hosted web apps and web platform innovations(来自 Kevin Hill 和 Kiril Seksenov)
我们的社区开源项目
- vorlon.JS(跨设备远程 JavaScript 测试)
- manifoldJS(部署跨平台托管 Web 应用)
- babylonJS(3D 图形轻松入门)
更多免费工具和后端 Web 开发内容