img标签响应式属性srcset和sizes属性的用法实践

发布时间:2022-05-21浏览次数:2253 次
先说几个常见的前端场景,毕竟脱离场景谈效用是没意义的。在制作前端响应式页面时,经常会遇到在不同分辨率的前端页面中,为达到更好的用户体验,需要使用不同分辨率的图片

先说几个常见的前端场景,毕竟脱离场景谈效用是没意义的。在制作前端响应式页面时,经常会遇到在不同分辨率的前端页面中,为达到更好的用户体验,需要使用不同分辨率的图片,比如,在4K的屏幕中,低分辨率的图片就会有非常明显的颗粒感。另外,有运维需求的开发同学,也会考虑到网络的节流和带宽问题,毕竟在低分辨率的设备屏幕下,去加载分辨率高,体积大的图像,不但会影响用户打开页面的加载速度,还会浪费带宽。

当然,也有前端开发的童鞋有如下这样的需求:在响应式页面中,经常会遇到PC电脑端和手机端需要加载不同的图片做轮播图的场景,电脑端我们经常使用的banner图片大多都是宽为1920,高度300-500左右的横幅图片,这样的横幅图片都有一个核心视区,一般设计时都会将重要的信息放在核心视区里,但是到了手机端,如果继续再使用这样尺寸的图片,且按100%的长度进行显示,那么压缩后的轮播图高度就会特别小,视觉上会别扭。当然也可以通过设置一个固定高度,然后再居中显示,但是这样的话,核心视区的东西又会显示不全。

理论上说,这些问题其实也都是img标签srcset属性可以处理的,但是需要强调说明的是,img的srcset属性原本的“业务范围”本是处理分辨率问题,随着浏览器技术的发展,对于宽度响应式问题也能处理,但不是最优方案。

那么今天我们讨论的img标签的srcset属性和sizes属性,是响应式前端切图中非常重要的组件,熟练使用,可以很好的解决上述问题。

一、srcset语法:

srcset属性定义了img属性允许浏览器加载的图像集,他的值是一个用逗号进行分割的字符串,用来定义img标签在不同条件下需要加载的图片地址,如果srcset只填写一个候选图片地址,且不带条件,则其功能与以前的src属性一致。区别在于:srcset可以定义一个或多个候选图片地址,并且,可以在候选图片地址后面加上可选的宽度或像素密度条件,用来表示,在指定宽度或像素密度的情况下加载对应的图片地址。多个候选图片地址用逗号分割。

语法:

<img srcset="候选地址1 [限制条件:宽度/像素密度],[候选地址2 [限制条件2]],... />

图片地址和条件描述符之间用空格分割,其余的空格(如逗号前后多余的空格)都会被自动忽略。

这里要重点讲述的是图片加载条件描述符,即在什么情况下使用该图片,条件描述符分两种情况:

1、限定条件可选

如果后端图片地址未加限定条件,则该地址为回退方案,即在未命中其他方案的情况下,使用该图片,否则使用命中的图片。

2、宽度限制条件(宽度描述符)

浏览器在下载图片前,它并不知道图片的尺寸,但是它知道它自身当前的视口宽度。因此,srcset允许我们通过指定浏览器视口的宽度,进行加载不同的图像。即指定在某个宽度下使用特定图片,需要加宽度限制条件,格式为:表示宽度的数字(单位为像素)+小写字母“w”(w可以理解为“width”的首字母),例如,如“800w”这样的宽度描述符,代表在像素密度未1时,渲染一个800像素宽的图像,另外需注意:指定的宽度必须为非零正数。

另外需要注意:备用候选图片:    

<img srcset="image/pic_300.jpg 300w,
                 image/pic_800.jpg 800w,
                 image/pic_1300.jpg 1300w"
    />

如上代码,未设置备用候选图片,这种情况下,假设像素密度DPR为1时,在浏览器视窗≤ 300px时,会显示pic_300的图片,在浏览器视窗≥ 300 且 ≤ 800时,显示pic_800,视窗≥800且≤1300时,显示pic_1300,当视口≥ 1300px时,因为没有专门的条件,所以浏览器会选择最靠近1300px的条件,即,还是会显示pic_1300。

但是,如果设置了备用候选图片后,情况就有些不一样了。如:

<img srcset="image/pic_300.jpg 300w,
                 image/pic_800.jpg 800w,
                 image/pic_1300.jpg 1300w,
                 image/pic_default.jpg"
    />

这里有多设置一条pic_default,即在未命中其他条件时,显示pic_default的图片,此时的命中条件就变成等于关系,即当浏览器视窗分别等于300px、800px、1300px的条件下,才会命中,其余情况下均显示pic_default的图片。

3、像素密度限制条件(像素密度描述符)

我们先来搞清楚像素密度这个概念,设备像素,英文为:devicePixelRatio,缩写为:DPR,指的是逻辑像素和物理像素之间的比例关系。设备的逻辑像素,即视觉上的物理像素宽度,因为这几个名词非常容易混淆,为了简明,我们将其称为硬件像素,而物理像素,可以理解为CSS像素,即在css中,占满一整行所需的px像素个数。

比如在iphone6手机的屏幕上,硬件像素(屏幕设备宽度)为375px,CSS像素(物理像素)为750px。则iphone6屏幕的像素密度DPR为:CSS像素 /  硬件像素 = 750 / 375=2。即在显示器上一个像素的宽度里,有2个物理像素。像素密度越高,屏幕显示越清晰。一般电脑的像素密度为1,也叫标准密度。

像素密度限制即指定在什么样的屏幕像素密度下应用什么样的图片的场景,格式为:像素密度dpr + 小写字母“x”,例如,我们要在iphone6手机上显示指定图片,则像素密度描述符需要写成 2x 或 2.0x,如果不写像素密度条件,则默认为1x。

注意:

  1. 1、以上几种限定条件可以混合使用(为多个图像指定相同的描述符,则只有第一个生效,后面的不生效)。
  2. 2、宽度描述符与像素密度描述符是相互影响的。

如以下代码:

<img srcset="image/pic_768.jpg?id=1 768w,
                 image/pic_992.jpg?id=1 992w,
                 image/pic_1200.jpg?id=1 1200w"
    />

为我们在不同终端上使用不同的图片。打开浏览器不断拖动使浏览器的宽度发生变化,我们会发现图片随着浏览器宽度的变化,也在变化。

为了观察的更直观,我们可以配合一段JS来时刻检测浏览器视窗的宽度和像素比:

$(window).resize(function (){
        $('.width').text($(this).width());
        $('.ratio').text(window.devicePixelRatio);// 获取像素比,JS原生写法
    })

我们还是继续使用上面的demo,探究下宽度限定符和设备像素的关系:

<img srcset="image/pic_300.jpg 800w,
                 image/pic_800.jpg 800w,
                 image/pic_1300.jpg 1300w"
    />

如下图,为在不同的设备像素DPR下,每张图片显示所需的视口宽度(viewport)条件:

DPRpic_300pic_800pic_1300
1viewport ≤ 300px300px ≤ viewport ≤ 800px800px ≤ viewport ≤ 1300px
2viewport ≤ 150px150px ≤ viewport ≤ 400px400px ≤ viewport ≤ 650px
3viewport ≤ 100px100px ≤ viewport ≤ 267px267px ≤ viewport ≤ 433px

二、sizes语法

sizes属性必须配合srcset属性一起使用才有效,单独使用无效。但是srcset可以单独使用。

sizes属性用来定义一组与srcset相匹配的媒体条件,指明当媒体条件为真时,什么样的图片尺寸是最佳选择—我们在之前已经讨论了一些提示。比如:(min-width:800px)可以理解为:可视窗口的最大宽度为800像素,即可视窗口宽度小于等于800px。

语法为:

sizes="媒体条件1 [槽的宽度1],[媒体条件2 [槽的宽度2]],..."

对于槽的宽度,可以使用像素或rem等长度单位,但是不可使用百分比。

在定义了sizes属性后,浏览器会依次执行以下操作:

1、查看当前设备宽度;

2、依次检查sizes属性列表中第一个为真的媒体条件;

3、查看该媒体条件对应的槽的大小;

4、通过槽的大小,加载对应的srcset列表中与槽的大小最接近的图像。

这也是为什么,sizes属性必须配合srcset属性,而srcset却可以脱离sizes属性使用的原因了。

三、chrome浏览器调试无效果的原因

我们设置如下的demo代码进行测试:    

<img srcset="image/33.jpg?id=1 768w,image/22.jpg?id=1 992w,image/11.jpg?id=1 1200w," />

实际测试过程中,火狐浏览器正常,但是谷歌Chrome浏览器,在将窗口从大拖小的过程中无变化,将窗口置于最小,刷新后,逐渐拖宽,这个过程中图片会变化,但是再将浏览器拖窄的过程中,图片不再变化,在调试工具中,点击对应图片,清除缓存后,又会恢复效果。

网上有说在隐私模式或无痕模式下测试,其实也会产生缓存。建议打开开发者调试工具(f12),在网络选项卡中,勾选停用缓存选项,注意,这里的停用缓存只有在调试工具打开的情况下,才有效。

目前针对chrome浏览器,缓存图片这种情况,暂时没有更好的解决方案,不过这种浏览器默认策略,仅仅影响的是演示阶段,在实际项目上线后,影响不是很大。如果您比较在意这一点,还可以使用picture属性来替换解决。

使用picture,可以很好的规避chrome这个烦人的缓存问题,代码如下:    

<picture>
        <source media="(max-width:500px)" srcset="image/pic_300.jpg" />
        <source media="(max-width:800px)" srcset="image/pic_800.jpg" />
        <source media="(min-width:800px)" srcset="image/pic_1300.jpg" />
        <img src="image/pic_300.jpg" />
</picture>

关于picture属性的使用,请移步查看:picture属性的使用。

扫一扫,在手机上查看