65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (13投票s)

2015年11月11日

CPOL

11分钟阅读

viewsIcon

22260

响应式网站的一个重要组成部分是响应式图片。在本文中,我们将更深入地了解 Web 上的响应式图片,并学习如何构建它们。

在这个互联互通的世界里,人们拥有各种各样的设备,确保您的网站在所有设备上都能无缝运行,这已不再是可选项,而是必需项。您的网站视图将不再仅仅来自单一分辨率的设备,或单一的设备形态。为了满足所有这些设备,您的网站需要具有响应性。

如果您熟悉响应式网页设计 (RWD),您可能已经了解了响应式设计所带来的复杂性(以及 Bootstrap 如何解决了其中的许多问题!)。响应式网站的一个重要组成部分是响应式图片。在本文中,我们将更深入地了解 Web 上的响应式图片,并学习如何构建它们。

什么是响应式图片?

简单来说,响应式图片是指根据用户查看您网站所使用的设备,在网页上以最佳形式显示的图片。“最佳形式”可能意味着多种含义:
 

  • 您希望根据用户的物理屏幕尺寸显示不同的图片资源。例如:您希望在 13.5 英寸的笔记本电脑和 5 英寸的手机(在最大化浏览器的情况下)上显示不同的图片资源。
  • 您希望根据设备的屏幕分辨率(或设备像素比,即设备像素与 CSS 像素的比率)显示不同的图片。
  • 如果您希望在浏览器支持的情况下显示特定格式的图片(例如 JPEG XR),那么您可能会这样做,因为该格式支持更高的压缩率。

响应式的构建块已包含在大多数现代浏览器中,包括 Microsoft Edge(从Windows Insider Build 10547 开始)。您可以在此处查看 srcset 等功能的 Web 平台状态。

如何启用响应式图片?

有多种方法可以启用图片的响应式行为。其中一种较旧的方法(不推荐)是使用简单的脚本,但这会导致一些问题。首先,如果脚本决定下载哪张图片,但脚本本身是在 HTML 中指定的图片下载之后加载的,那么您可能会下载两张图片。其次,如果您在 HTML 中没有指定任何图片,并且只想加载由脚本定义的图片,那么对于禁用了脚本的浏览器,您将完全看不到图片。

因此,我们需要一种更好的方法来处理响应式图片。幸运的是,我们有了!推荐的方法是使用

  1. srcset 属性
  2. sizes 属性
  3. 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. 对于设备像素比为 1,将使用图片 space-needle.jpg。
  2. 对于设备像素比为 2,将使用图片 space-needle-2x.jpg。
  3. 对于设备像素比为 3,将使用图片 space-needle-hd.jpg。

src 属性用作不支持 srcset 实现的浏览器的回退。

这效果很好。使用 x 描述符,您将始终在具有相似设备像素比的设备上获得相同的图片——即使这意味着您在具有相同设备像素比的 13.5 英寸笔记本电脑和 5 英寸手机上获得相同的图片。

现在假设我们希望在更大的或更小的视口上显示不同尺寸(高度、宽度)的图片。这就是 srcsetw 描述符和一个新属性——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 描述符的 sizessrcset(再次,制作同一张图片的多个资源)。
我担心如果我对较小的屏幕尺寸使用相同的图片,我的图片的主要主体可能会变得太小。我希望在不同的屏幕尺寸上显示不同的图片(更侧重于主要主体),但我仍然希望根据设备像素比显示同一图片的各个资源,并且我希望根据视口自定义图片的宽度和高度。 ?

“?”的解决方案是 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 属性,并且可以具有 sizesmediatype 属性。必须在 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。

整合所有内容

在了解了响应式图片的工作原理后,让我们来看一个结合了所有三种元素——srcsetsizespicture——的完整示例。

<!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 上使用免费工具。

我们工程师和布道者的更深入的学习

我们的社区开源项目

更多免费工具和后端 Web 开发内容

© . All rights reserved.