用HTML响应式图像提高性能

166 阅读10分钟

当谈到响应式图像时,我们通常关注的是使图像适应不同视口尺寸的CSS技术,例如将max-width 属性设置为百分之百。然而,仅仅使用CSS来使图像响应并不能提高性能和页面加载时间,因为你仍然在为所有设备提供相同大小的图像。例如,在移动设备上加载一个2000px的图片,会带来巨大的(而且是不必要的)开销。

幸运的是,HTML也有自己的语法、元素和响应式图像的属性,让你为不同的视口尺寸、分辨率和其他条件提供不同的图像。在本指南中,我们将研究如何在HTML中添加响应式图像,并讨论以下功能。

  • <img> 元素
  • srcsetsizes 属性
  • xw 描述符
  • <picture><source> 元素
  • mediatype 属性

标准图像语法

要在HTML中添加响应式图像,你的出发点始终是标准的图像语法,包括 [<img>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img)元素和srcalt 属性组成。

<img src="images/myimage.jpg alt="my image">

对于src 属性,你可以使用绝对路径(从http://https:// 协议开始)或相对路径 - 我在上面使用了后者。

你总是需要在这个标准的<img> 定义的基础上 "建立 "响应的图像语法;这也确保了向后的兼容性。

srcset 属性

[srcset](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-srcset)属性是一个与图像相关的HTML元素的可选属性,包括<img> 标签。你可以用它来为用户设备的某些特征指定不同的图像源,如视口大小或像素密度。用户的浏览器将只加载最适合用户设备的图像--这可能意味着显著的性能提升。

当使用srcset 属性时,你应该在不同的尺寸下添加相同的图片。这是因为这个属性只是给用户的浏览器一个提示,它仍然可以加载不同的图像,因为它还考虑了其他的事情,比如网络的带宽。如果你使用srcset ,浏览器会认为所有的图像源在视觉上是相同的。如果你想提供不同外观的图片,你需要使用<picture><source> 元素--我们将在后面研究它们。

有两种方法可以用srcset 属性提供不同尺寸的图像。

  • 使用x 描述符。
    • 你可以根据用户设备的像素密度指定不同的图像源
    • 你可以为低分辨率和高分辨率的设备提供不同的图像
  • 使用w 描述符和sizes 属性。
    • 术语 "w 描述符 "是指 "宽度描述符"。
    • 你可以根据图片的宽度指定不同的图片来源
    • 浏览器同时考虑像素密度和布局尺寸(它需要为图像分配的空间)。

现在,让我们来看看各自的语法。

带有x 描述符的srcset 属性(s)

使用下面的HTML,你可以为低分辨率和高分辨率的显示器提供图像。

<img src="images/myimage.jpg" srcset="images/myimage-2x.jpg 2x" alt="my image">

第二张图片,myimage-2x.jpg ,是默认图片的两倍(例如1280x960px,而不是640x480px),但它只会在高分辨率的屏幕上加载。将由用户的浏览器来决定提供哪张图片,主要是根据显示屏的像素密度。

请注意,你应该在src 属性中添加较小的图片,因为这将是默认的。对于srcset 属性,你还需要使用2x 描述符,这样浏览器就会知道这是为高分辨率屏幕准备的图像。

你也可以给srcset 属性添加一个以上的值。例如,用下面的代码,你可以为4K显示器提供图像。

<img src="images/myimage.jpg" srcset="images/myimage-2x.jpg 2x, images/myimage-4x.jpg 4x" alt="my image">

要向srcset 添加一个以上的图像源,你需要使用各自的x 描述符(2x,3x,4x, 等等),并用逗号分隔这些值对。

srcset 属性与w 描述符(s)和sizes 属性

如果你想同时针对用户设备的像素密度和布局尺寸,你需要将srcset 属性与一个或多个width 描述符和sizes 属性一起使用。

一个w 描述符定义了源图像的宽度。例如,600w 表示图像是600px宽。只要你用逗号把它们分开,你就可以在srcset 属性中添加任意多的图像源,像这样。

<img  src="images/myimage-small.jpg" 
    srcset="images/myimage-small.jpg 300w,
    images/myimage-medium.jpg 600w,
    images/myimage.jpg 1200w,
    images/myimage.jpg 1800w" 
    sizes="(max-width: 500px) 100vw,
    (max-width: 1000px) 90vw,
    calc(60vw - 20px)" 
    alt="my image">

如果你使用width 描述符,你也需要使用sizes 属性--否则,浏览器将无法找出要选择的图像源。sizes 属性经常被误解,因为人们往往认为sizes 属性的媒体条件中使用的宽度值与srcset 属性中使用的w 值(300w,600w, 等等)有关--然而,它们是相互独立的。

sizes 属性有两个目的。

  1. 告知浏览器它需要为图像分配的空间,这取决于版面设计
  2. 允许浏览器使用可用图像的宽度(由w 描述符定义)和屏幕的像素密度来挑选最合适的图像。
    1. 例如:对于较小的全高清屏幕--比如说13.3英寸--浏览器可以选择相同的图像,比如说1200w ,而对于较大的低分辨率屏幕--比方说17.3英寸。浏览器的选择还取决于可用图像的尺寸分布和其他条件,因为正如我在上面提到的,srcsetsizes 属性对浏览器来说是可选的,但不是必须的(相对于<picture><sources> 元素)。

在上面的代码例子中,我在sizes 属性中定义了三种布局。在小于500px的视口上,图像将横跨视口宽度的100%(100vw )。在小于1000px的中型视口上,图像将需要视口宽度的90% (90vw)。而在大于1000px的视口上,浏览器将需要分配视口宽度的60%,减去20px的左右边距(calc(60vw - 20px))。后者也是默认值,所以我没有在这里使用任何媒体条件

使用媒体条件

你可以使用任何数量的媒体条件来定义不同的布局和图像在每个布局中所需要的空间,但需要注意的是,在sizes 属性中添加媒体条件是可选的。它只需要包括一个默认值,如果你的布局在所有视口尺寸下看起来都一样,你就不需要使用任何媒体条件。例如,上面的例子也可以是这样的。

<img  src="images/myimage-small.jpg" 
    srcset="images/myimage-small.jpg 300w,
    images/myimage-medium.jpg 600w,
    images/myimage.jpg 1200w,
    images/myimage.jpg 1800w" 
    sizes="60vw" 
    alt="my image">

注意:你会发现有些教程说你可以同时使用xw 描述符,但根据文档,这两个描述符不应该同时使用。仔细想想这确实有道理,因为当你使用w 描述符时,浏览器也会考虑像素密度。

因此,如果你只想针对像素密度,就使用x 描述符。如果你想同时针对像素密度和布局,则使用w 描述符。

<picture><source> 元素

如果你想以不同的尺寸提供相同的图片,那么与srcset 属性和xw 描述符一起使用的<img> 元素是一个很好的解决方案,但有时你会想为不同的用户代理加载视觉上不同的图片。

有两个主要的用例,涵盖了你可能想这样做的原因。

  • 为不同的媒体条件使用不同的艺术指导,例如,同一图像的放大和缩小版本
  • 使用不同的图像格式,这样你就可以为现代浏览器提供下一代图像

针对这些情况,HTML有两个元素。 [<picture>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture)[<source>](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source).后者可以用来为<picture><audio><video> 等元素指定不同的媒体资源。

现在,让我们看看这个语法是什么样子的。

具有不同艺术方向的图像源

假设你有以下图片。

Large flamingos sample

图片由Summer Li拍摄,来自Pexels

对于大屏幕来说,这是一张完美的图片,但对于中等大小的屏幕,你可能想提供一张尺寸较小的近景照片。

Medium sized flamingos sample, zoomed in

而在小屏幕上,你只想在一个更小的图像中显示其中一只火烈鸟。

Small, profile flamingos sample

你可以用下面的HTML代码来定义这三种图像源。

<picture>
  <source srcset="images/flamingos-closer.jpg" media="(min-width: 768px) and (max-width: 1199px)">
  <source srcset="images/flamingos-far.jpg" media="(min-width: 1200px)">
  <img src="images/flamingo-profile-small.jpg" alt="flamingo">
</picture>

正如你在上面看到的,我们把最小的、最接近的图像作为默认值,并为每个图像源定义了一个相关的媒体条件。

如果你愿意,你也可以在每个srcset 属性中使用前述的xw 描述符来指定一个以上的图像,例如。

<picture>
    <source srcset="images/flamingos-closer.jpg, images/flamingos-closer-2x.jpg 2x" media="(min-width: 768px) and (max-width: 1199px)">
  <source srcset="images/flamingos-far.jpg, images/flamingos-far-2x.jpg 2x" media="(min-width: 1200px)">
  <img src="images/flamingo-profile-small.jpg" srcset="images/flamingo-profile-small-2x.jpg 2x" alt="flamingo">
</picture>

注意,使用media 属性,你可以同时针对宽度和任何其他媒体特征,如方向、长宽比等。

如果你将<picture> 元素与<source> 标签一起使用,用户的浏览器仍将只加载一张图片--最合适的一张--但现在,媒体条件不像以前那样是一个提示或一个选项。相反,它是一条浏览器在任何情况下都必须遵循的规则。换句话说,浏览器将假定图像源在视觉上是不同的,并相应地处理它们。

不同格式的图像源

除了媒体条件,你也可以提供不同格式的图像。如果你想使用下一代图像格式,如AVIF或WebP,这可能特别有用,这些格式尺寸较小(本身可以提高性能),但不被旧的浏览器支持。

在这里,你需要使用type 属性来定义每个图像源的MIME类型

<picture>
  <source srcset="images/myimage.avif" type="image/avif">
  <source srcset="images/myimage.webp" type="image/webp">
  <img src="images/myimage.jpg" alt="my image">
</picture>

如果你使用上面的代码,用户的浏览器将逐一检查连续的MIME类型--因此,添加你希望首先检查的类型(我在上面的例子中使用AVIF)。

从技术上讲,你也可以在每个typemedia 属性中一起使用<source> 元素 - 但是,请注意这可能会增加很多额外的复杂性。

<picture>
  <source srcset="images/flamingos-closer.webp" media="(min-width: 768px) and (max-width: 1199px)" type="image/webp">
  <source srcset="images/flamingos-closer.jpg" media="(min-width: 768px) and (max-width: 1199px)" type="image/jpeg">
  <source srcset="images/flamingos-far.webp" media="(min-width: 1200px)" type="image/webp">
  <source srcset="images/flamingos-far.jpg" media="(min-width: 1200px)" type="image/jpeg">
  <source srcset="images/flamingo-profile-small.webp" type="image/webp">
  <img src="images/flamingo-profile-small.jpg" alt="flamingo">
</picture>

浏览器支持

浏览器对与响应式图像有关的HTML语法的支持相对较好。

  • Edge 16+、Firefox 38+、Chrome 38+和Safari 9+都支持 srcsetsizes 属性,但任何版本的Internet Explorer都不支持它们。
  • Edge 13+、Firefox 38+、Chrome 38+和Safari 9.1+支持 <picture> 元素,但任何版本的Internet Explorer都不支持它。
  • <source> 元素被 Internet Explorer 9+、Edge 12+、Firefox 15+、Chrome 90+ 和 Safari 14.1+支持

由于Chrome和Safari开始支持<source> 元素的时间相对较晚,在这四个与响应式图像有关的HTML功能中,它的浏览器支持程度最低。

另外,响应式图像的语法会优雅地退化。如果一个浏览器不支持一个或多个元素或属性,它将简单地使用添加到支持度很高的<img> 元素中的默认图像。

收尾工作

在HTML中添加不同的图像源,为每个用户代理提供最有效的图像,可以带来巨大的性能提升,尤其是在移动设备上。然而,复杂的语法会使你的编码工作流程过于复杂,而且你的代码更难阅读。

从本质上讲,这是在复杂性和性能之间的权衡,所以你需要决定对你来说是否值得这么麻烦的事情。显然,图像性能在图像密集的网站上更重要,如果你在任何时候屏幕上只有一两张图像,图像性能可能就不那么重要了。

你也可以把这个过程自动化。NetlifyCloudflare等CDN和WordPress等CMS已经有了内置的图像优化功能--它们会生成同一图像的多个版本,添加<picture> ,应用媒体条件,等等。还有一些开源的解决方案可以帮助你实现自动化,如Image ResponsiverGet Sizes工具。

最后,别忘了,本指南只讨论了如何在HTML中提供响应式图像。你仍然需要使用CSS来使HTML添加的图像适应设计,比如调整widthmax-width 属性,或者使用响应式图像网格。

The postImproving performance with HTML responsive imagesappeared first onLogRocket Blog.