作者 | Chameera Dulanga
译者 | 王强
策划 | 李俊辰
本文最初发布于 Medium 网站,经原作者授权由 InfoQ 中文站翻译并分享。
在用户界面中使用图像和动画已成为现代 Web 应用程序中的常见情况。尽管这些现代设计都致力于改善应用程序的用户体验,但如果这些图像在所有设备上都没有良好的响应,事情就会适得其反。
作为开发人员,我们必须满足所有这些要求。但大多数时候,由于我们正在寻求更高级别的解决方案,因此会忽略一些可能会带来巨大影响的小事。
在 picture 标签和 img 标签之间做选择可能是一个很小的决策,但如果你做出了正确的选择,就能改善用户体验和性能。
本文将讨论 picture 和 img 标签之间的区别,以及 picture 标签比 img 标签更好用的原因所在。
下次当你创建一个 React 图像组件时,请一定要在其中实现你即将在本文中学习的最佳实践。根据接收到的 props 返回正确的标签,并处理好所有必要的回退。你甚至可以在 Bit.dev 的组件中心上共享它,这样你的团队和你自己将来都能重用它。这样,你就会拥有一个优化极佳的图像组件,可以毫不犹豫地用在所有 Web 项目中。
img 标签现在已经不够优秀
众所周知,很长一段时间以来,img 标签一直是 HTML 的核心元素之一,它的简单性和可用性是毋庸置疑的。
然而,随着各种屏幕尺寸、分辨率的设备和复杂用户需求的发展,img 标签的响应性和在多设备应用中使用的能力开始受到质疑。
所有这些问题可以归结为两大方面:
- 分辨率切换——为小屏幕设备提供较小尺寸图像的问题。
- 图像切换——在不同屏幕上显示不同图像的问题。
现在,我们来看看如何解决这些问题,以及 picture 标签的其他特性。
使用 srcset 和 size 属性切换分辨率
如前所述,当今的网页设计师经常使用高分辨率图像来增加用户吸引力。但是作为开发人员,我们必须非常小心地选择正确的 HTML 元素。
假设你对高分辨率图像使用简单的 Img 标签。在这种情况下,运行你应用程序的每台设备都会使用相同的图像,并且肯定会导致屏幕分辨率较低的设备(如移动设备)出现性能问题。
这可能会导致更长的图像加载时间以及从上到下一块一块地图像加载。
通过使用 srcset 和 size 属性,可以使用 picture 图片标签轻松解决这一问题。
代码语言:javascript复制<picture>
<source
srcset="small-car-image.jpg 400w,
medium-car-image.jpg 800w,
large-car-image.jpg 1200w"
sizes="(min-width: 1280px) 1200px,
(min-width: 768px) 400px,
100vw">
<img src="medium-car-image.jpg" alt="Car">
</picture>
srcset 属性接收多个图像,其宽度都以像素为单位,浏览器使用这些值在提供的图像之间进行选择。在上面的示例中,同一图像有 3 个版本,具有 3 种不同的尺寸。
Sizes 属性定义图像将在屏幕上占据的空间。在上面的示例中,如果屏幕的最小宽度为 1280px,则图像将占据 1200px。
代码语言:javascript复制话虽如此,建议不要仅将 picture 标签用于分辨率切换,因为可以使用更新版本的 Img 标签(具有更多的浏览器支持)来实现此目的。
<img srcset="small-car-image.jpg 400w,
medium-car-image.jpg 800w,
large-car-image.jpg 1200w"
sizes="(min-width: 1280px) 1200px,
(min-width: 768px) 400px,
100vw"
src="medium-car-image.jpg" alt="Car">
但在大多数情况下,我们需要同时处理“分辨率切换”和“图像切换”,并且 picture 标签是最好的解决方案。
因此,让我们看看如何使用 picture 标签解决图像切换问题。
使用媒体属性切换图像
图像切换背后的主要思想是根据设备的屏幕尺寸显示不同的图像。在大多数情况下,切换到移动设备时,在大屏幕上看起来很棒的图像可能会被裁剪或显得很小。
我们可以为不同的屏幕尺寸提供不同版本的图像来解决这一问题。这些不同的版本可以是同一图像的横向,纵向或任何自定义版本。
我们可以使用 picture 标签中的多个 source 标签轻松实现分辨率切换。
代码语言:javascript复制<picture>
<source ....>
<source ....>
<source ....>
</picture>
然后,我们可以使用 media 属性定义使用这些源的不同媒体条件。我们还可以按照上一节中讨论的类似方式使用 srcset 和 size 属性。以下示例显示了使用 picture 标签解决“图像切换”和“分辨率切换”的完整示例。
代码语言:javascript复制<picture>
<source media="(orientation: landscape)"
srcset="land-small-car-image.jpg 200w,
land-medium-car-image.jpg 600w,
land-large-car-image.jpg 1000w"
sizes="(min-width: 700px) 500px,
(min-width: 600px) 400px,
100vw">
<source media="(orientation: portrait)"
srcset="port-small-car-image.jpg 700w,
port-medium-car-image.jpg 1200w,
port-large-car-image.jpg 1600w"
sizes="(min-width: 768px) 700px,
(min-width: 1024px) 600px,
500px">
<img src="land-medium-car-image.jpg" alt="Car">
</picture>
如果屏幕方向是横向,则浏览器将显示第一组图像;如果屏幕方向是纵向,则浏览器将使用第二组图像。除此之外,你还可以将 media 属性与 max-width 和 min-width 参数一起使用:
代码语言:javascript复制<picture>
<source media="(max-width: 767px)" ....>
<source media="(min-width: 768px)" ....>
</picture>
最后一个 img 标签用于向后兼容不支持 picture 标签的浏览器。
用于受部分支持的图像类型
随着技术的飞速发展,新的图像格式也在不断涌现。其中一些格式(例如 webp、svg 和 avif)提供了更高的用户体验水平。
另一方面,某些浏览器对这些现代图像类型存在限制,如果我们不使用兼容的图像类型,事情将会适得其反。
代码语言:javascript复制但是,我们可以使用 Picture 标签轻松解决这个问题,因为它允许我们在其中包含多个来源。
<picture>
<source srcset="test.avif" type="image/avif">
<source srcset="test.webp" type="image/webp">
<img src="test.png" alt="test image">
</picture>
上面的示例包括 avif、webp 和 png 格式的三种图像类型。首先,浏览器将尝试 avif 格式;如果失败,则将尝试 webp 格式。如果浏览器不支持这两种方式,它将使用 png 图像。
Chrome 宣布“DevTools 将在 Rendering 选项卡中提供两个新的仿真,以模拟部分受支持的图像类型”后,picture 标签用起来就更有意思了。
从 Chrome 88 开始,你可以使用 Chrome DevTools 检查浏览器与图像类型的兼容性。
使用 ChromeDevTools 进行图像兼容性仿真
结语
尽管我们讨论了为什么 picture 标签比 img 标签更好用的原因,但我必须坚持一点,那就是 img 标签并没有消亡,或者说不会很快消亡。
如果我们能明智地使用 img 提供的属性,如 srcset 和 size,则可以从中获得最大收益。例如,我们可以只使用 img 标签来解决“分辨率切换”问题。
另一方面,我们可以使用 picture 标签的媒体查询和其他属性轻松实现分辨率切换和图像切换。
用于部分受支持的图像类型和 Chrome DevTools 的支持可以被认为是 picture 标签的额外优势。
但是,这两种元素各有利弊。因此,我们必须根据我们的需求仔细考虑和使用最合适的元素。
谢谢你的阅读!
延伸阅读
https://blog.bitsrc.io/why-you-should-use-picture-tag-instead-of-img-tag-b9841e86bf8b