HTML应用——响应式图片

本文最后更新于:8 个月前

根据设备情况自动加载不同的图像资源,称为“响应式图片”。本文介绍了两种实现响应式图片的HTML语法,并通过实践案例探讨了两种方式各自的特点和注意事项

HTML应用——响应式图片

前言

图片能够根据浏览器所处的不同的设备条件,切换不同的图片资源,以达到适应设备变化,称为“响应式图片”。

通过HTML、CSS、JavaScript都可以实现响应式图片设计,但是通过HTML方法实现是最理想的解决方式。因为<img>标签的加载发生在html解析过程中,而CSS和JS的加载和发挥作用都在这之后,所以使用CSS、JS的实现方式,需要先把原始图像加载,再根据情况替换图像,相当于多做了一次无意义的加载。

下面就介绍两种 HTML 实现方式

一、方式一:img + srcset + sizes

<img>标签可以使用两个新属性:srcsetsizes,来提供更多的图像资源选择,以帮助浏览器选择一个合适的资源。

1、应用一:响应不同的尺寸

根据不同的视口尺寸(如宽度),选择不同大小的图片

使用方法:

srcset属性,包含两个值

  1. URL,图像资源链接
  2. 图像的宽度,注意:单位是w而不是px

sizes属性,也是包含两个值

  1. media query,媒体查询条件
  2. 条件为true时,对应图像占据的宽度,单位px

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<img srcset="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_300,m_lfit 300w,
https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_600,m_lfit 600w,
https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_900,m_lfit 900w"
sizes="(max-width:500px) 300px,
(max-width:800px) 600px,
(max-width:1200px) 900px,
1200px"
src="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg" alt="提示">

<!--
解析:
浏览器会查看设备当前的视口宽度,然后对sizes中的媒体查询条件进行判断,以上面的sizes为例:
如果视口宽度在1-500px之间,将应用sizes第一条,给图片设置宽度为500px,然后在srcset中寻找最接近300px的300w,加载300w对应的资源
如果视口宽度在401-800px之间,将应用sizes第二条,给图片设置宽度为600px,然后在srcset中寻找最接近600px的600w,加载600w对应的资源
如果视口宽度在801-1200px之间,将应用sizes第一条,给图片设置宽度为900px,然后在srcset中寻找最接近900px的900w,加载900w对应的资源

一个有意思的现象:
如果视口宽度从小到大变化,比如从[1-500px]放大到[501-800px]再放大到[801-1200px],那么浏览器会逐次变更对应的资源
但是反向操作,即视口宽度从大变到小,则不会变更资源
-->

浏览器工作流程:

  1. 查看设备宽度
  2. 从前往后,检查sizes列表中哪个媒体条件是第一个为真,取最后一个为真的条件
  3. 查看给予该媒体查询的槽大小
  4. 加载srcset列表中引用的最接近所选的槽大小的图像

探究:sizes的匹配机制

1
2
3
4
5
6
7
8
9
10
11
12
<!--下例中sizes的排列顺序并不规则,目的是为了测试sizes的匹配机制。实际使用时,强烈建议按照顺序来声明!!-->
<img srcset="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_300,m_lfit 300w,
https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_400,m_lfit 400w,
https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_600,m_lfit 600w,
https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_900,m_lfit 900w"
sizes="
(max-width:800px) 600px,
(max-width:500px) 400px,
(max-width:400px) 300px,
(max-width:1200px) 900px,
1200px"
src="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg" alt="提示">

经过实践测试,观察到sizes属性的匹配机制是:从上到下匹配,遇到匹配为true的语句时,就停止。

比如上面这个例子,视口宽度在 4百多px的时候,刷新页面进行加载,显示加载的资源是..._600这个文件。

2、应用二:响应不同的分辨率

先说结果:实测结果翻车了,所以这种应用方式不推荐使用,下面保留了探究过程,仅供参考

首先普及一下「像素」的概念

「像素」分为两种:

  • 设备像素,表示屏幕上的真实像素点
  • CSS像素,CSS中的长度单位,px

一般来说,1个设备像素 = 1个CSS像素

但是在一些高分辨率屏幕中,会出现 2个设备像素 = 1个CSS像素 的情况

这两者之间的关系叫做「设备像素比」,在JavaScript中,可以通过window.devicePixelRatio字段查看

这里参考了:设备像素、设备独立像素、CSS 像素 - 简书 (jianshu.com)

使用方法:

srcset属性,包含两个值

  1. URL,图像资源链接
  2. 设备像素比,单位x

实现效果:在不同分辨率的设备中,使用不同大小的图像,但是最终屏幕显示的尺寸是一样的。简单来说,就是高分辨率设备用高清图片,低分辨率设备用低清图片。

1
2
3
4
<img srcset="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_500,m_lfit,
https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_1000,m_lfit 2x"
src="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg" alt="提示">
<!--1x是默认值,所以不需要写出来-->
1
2
3
img {
width: 500px;
}

解析:这个例子中,通过CSS样式,固定图片宽度为500px。然后再srcset中提供不同设备像素比设备所对应的资源链接。浏览器将自动根据设备的实际参数决定加载的资源

「设备像素比」= 2 的设备,加载如下:经过测量,发现图片的实际宽度是1000px,也就是说CSS规定的width:500px并没有发挥作用。所以从结果看来,是翻车了,并没有实现我们所预期的固定宽度的效果

image-20221104205402637

「设备像素比」= 1 的设备,加载如下:经过测量,实际宽度为500px

image-20221104205452620

二、方式二:picture + source

<picture> 元素包含两个标签:一个或多个 <source> 标签和一个 <img> 标签。

浏览器将查找媒体查询与当前视口宽度匹配的第一个 <source> 元素,然后显示正确的图像(在 srcset 属性中指定)。 <img> 元素是 <picture> 元素的最后一个子元素,如果没有 source 标签匹配,则作为后备选项。

1
2
3
4
5
<picture>
<source media="(max-width: 799px)" srcset="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_500,m_lfit">
<source media="(min-width: 800px)" srcset="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg?x-oss-process=image/resize,w_800,m_lfit">
<img src="https://qiuzcc-typora-images.oss-cn-shenzhen.aliyuncs.com/images/2022/202210121140688.jpg" alt="图片说明文字">
</picture>

要决定加载哪个 URL,user agent 检查每个 <source>srcsetmediatype 属性,来选择最匹配页面当前布局、显示设备特征等的兼容图像。

  • media属性

    从上到下匹配source元素的media条件,如果当前匹配结果为false,那么这个source元素被跳过

  • type属性

    指定资源的MIME类型,如果浏览器不支持该类型,那么这个source元素被跳过

实测结果

image-20221104210628870

实践发现,在视口宽度发生变化时,浏览器会不断地去比对source标签,每次匹配结果发生变化时,都会重新加载对应的资源(从右侧的网络加载情况可以看到,而这一点与方式一有很大区别),可以看下图对比一下

image-20221104211639821

方式一:img+srcset+sizes这种方式,只有在宽度从小变大的过程中,会触发新的加载。在宽度从大变小大过程时,则直接复用已经加载的大图

参考链接

响应式图片 - 学习 Web 开发 | MDN (mozilla.org)


HTML应用——响应式图片
http://timegogo.top/2022/11/04/HTML/HTML应用——响应式图片/
作者
丘智聪
发布于
2022年11月4日
更新于
2023年7月16日
许可协议