3

现代图片性能优化及体验优化指南 - 响应式图片方案 - ChokCoco

 1 year ago
source link: https://www.cnblogs.com/coco1s/p/17139699.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文是系列第二篇。系列文章:

  1. 现代图片性能优化及体验优化指南 - 图片类型及 Picture 标签的使用

图片资源,在我们的业务中可谓是占据了非常大头的一环,尤其是其对带宽的消耗是十分巨大的。

对图片的性能优化及体验优化在今天就显得尤为重要。本文,就将从各个方面阐述,在各种新特性满头飞的今天,我们可以如何尽可能的对我们的图片资源,进行性能优化及体验优化。

适配不同的屏幕尺寸及 DPR

下一个模块,我们来看看图片资源如何更好的适配不同的屏幕尺寸。

这里首先会涉及一个预备知识,屏幕的 DPR 值,那么,什么是 DPR 呢?要了解 DPR,又需要知道什么是设备独立像素 以及 物理像素

设备独立像素

以 iPhone6/7/8为例,这里我们打开 Chrome 开发者工具:

885a3be2737145ceb4b728ab37bd6e56~tplv-k3u1fbpfcp-watermark.image?

这里的 375 * 667 表示的是什么呢,表示的是设备独立像素(DIP),也可以理解为 CSS 像素,也称为逻辑像素:

设备独立像素 = CSS 像素 = 逻辑像素

如何记忆呢?这里使用 CSS 像素来记忆,也就是说。我们设定一个宽度为 375px 的 div,刚好可以充满这个设备的一行,配合高度 667px ,则 div 的大小刚好可以充满整个屏幕。

OK,那么,什么又是物理像素呢。我们到电商网站购买手机,都会看一看手机的参数,以 JD 上的 iPhone7 为例:

6cd05b8490264dc8933b526b841c0180~tplv-k3u1fbpfcp-watermark.image?

可以看到,iPhone7 的分辨率是 1334 x 750,这里描述的就是屏幕实际的物理像素。

物理像素,又称为设备像素。显示屏是由一个个物理像素点组成的,1334 x 750 表示手机分别在垂直和水平上所具有的像素点数。通过控制每个像素点的颜色,就可以使屏幕显示出不同的图像,屏幕从工厂出来那天起,它上面的物理像素点就固定不变了,单位为pt。

设备像素 = 物理像素

DPR(Device Pixel Ratio) 设备像素比

OK,有了上面两个概念,就可以顺理成章引出下一个概念。DPR(Device Pixel Ratio) 设备像素比,这个与我们通常说的视网膜屏(多倍屏,Retina屏)有关。

设备像素比描述的是未缩放状态下,物理像素和设备独立像素的初始比例关系。

简单的计算公式:

DPR = 物理像素 / 设备独立像素

我们套用一下上面 iPhone7 的数据(取设备的物理像素宽度与设备独立像素宽度进行计算):

iPhone7’s DPR = iPhone7’s 物理像素宽度 / iPhone7's 设备独立像素宽度 = 2

750 / 375 = 2
或者是 1334 / 667 = 2

可以得到 iPhone7 的 dpr 为 2。也就是我们常说的视网膜屏幕。

视网膜(Retina)屏幕是苹果公司"发明"的一个营销术语。 苹果公司将 dpr > 1 的屏幕称为视网膜屏幕。

9186437d2a1e4785a135e67d67b7d24f~tplv-k3u1fbpfcp-watermark.image?

在视网膜屏幕中,以 dpr = 2 为例,把 4(2x2) 个像素当 1 个像素使用,这样让屏幕看起来更精致,但是元素的大小本身却不会改变:

d5cd6add188d48489d46cd1346b07be7~tplv-k3u1fbpfcp-watermark.image?

OK,我们再来看看 iPhone XS Max:

e6c3a2d75b324db9a3bc153f07bb62f1~tplv-k3u1fbpfcp-watermark.image?

它的物理像素如上图是 2688 x 1242

fd3f0b4606b24beb8832e33d5f378c33~tplv-k3u1fbpfcp-watermark.image?

它的 CSS 像素是 896 x 414,很容易得出 iPhone XS Max 的 dpr 为 3。

为不同 DPR 屏幕,提供恰当的图片

那么,DPR 和图片适配有什么关系呢?

举个例子,同样的 CSS 像素大小下,屏幕如果有不同 DPR,同样大小的图片渲染出来的效果不尽相同。

我们以 dpr = 3 的手机为例子,在 300 x 389 CSS 像素大小的范围内,渲染 1倍/2倍/3倍 图的效果如下:

6e756e482af44fa29cb7da9f439b2732~tplv-k3u1fbpfcp-watermark.image?

实际图片所占的物理像素为 900 x 1167。

可以看到,在高 DPR 设备下提供只有 CSS 像素大小的图片,是非常模糊的。

因此,为了在不同的 DPR 屏幕下,让图片看起来都不失真,我们需要为不同 DPR 的图片,提供不同大小的图片。

那么,有哪些可行的解决方案呢?

方案一:无脑多倍图

假设,在移动端假设我们需要一张 CSS 像素为 300 x 200 的图像,考虑到现在已经有了 dpr = 3 的设备,那么要保证图片在 dpr = 3 的设备下也正常高清展示,我们最大可能需要一张 900 x 600 的原图。

这样,不管设备的 dpr 是否为 3,我们统一都使用 3 倍图。这样即使在 dpr = 1,dpr = 2 的设备上,也能非常好的展示图片。

当然这样并不可取,会造成大量带宽的浪费。

现代浏览器,提供了更好的方式,让我们能够根据设备 dpr 的不同,提供不同尺寸的图片。

方案二:媒体查询

方案二,我们可以考虑使用媒体查询。到今天,我们可以通过相应的媒体查询,得知当前的设备的 DPR 值,这样,我们就可以在对应的媒体查询中,使用对应的图片。

像是这样:

#id { 
    background: url([email protected]) 
}
@media (device-pixel-ratio: 2) {
    #id { 
        background: url([email protected]) 
    }
}
@media (device-pixel-ratio: 3) {
    #id { 
        background: url([email protected]) 
    }
}

这个方案的缺点在于:

  1. 要写的代码可能太多了,而且,可能存在一些介于 12,23 之间的 DPR 值,不好穷举出所有场景
  2. 需要注意语法需要的兼容性,需要添加前缀,譬如 -webkit-min-device-pixel-ratio,当然这个可以由 autoprefixer 辅助解决

方案三:CSS 配合 image-set 语法

image-set 属于 CSS background 中的一种语法,image-set() 函数为设备提供最合适的图像分辨率,它提供一组图像选项,每个选项都有一个相关的 DPR 声明,浏览器将从中选择最适合设备的图像进行设置。

什么意思呢,来看看代码:

.img {
    /* 不支持 image-set 的浏览器*/
    background-image: url('../[email protected]');

    /* 支持 image-set 的浏览器*/
    background-image: image-set(
        url('./[email protected]') 2x,
        url('./[email protected]') 3x
    );
}

这样一看,作用应该很清晰了。对于支持 image-set 语法的浏览器:

  1. 如果其设备对应的 DPR 为 2,会选取这条 url('./[email protected]') 2x 记录,也就是最终生效的 URL 是 './[email protected]'
  2. 如果其设备对应的 DPR 为 3,会选取这条 url('./[email protected]') 3x 记录,也就是最终生效的 URL 是 './[email protected]'

其中的 2x3x 就是用于匹配 DRP的。

使用 image-set 的一些痛点与媒体查询方案类似。代码量与兼容性语法,而且难以匹配所有情况。

方案四:srcset 配合 1x 2x 像素密度描述符

简单来说,srcset 可以根据不同的 dpr 拉取对应尺寸的图片:

<div class='illustration'>
   <img src='illustration-small.png'
       srcset='images/illustration-small.png 1x,
               images/illustration-big.png 2x'
   >
</div>

上面 srcset 里的 1x,2x 表示 像素密度描述符,表示

  • 当屏幕的 dpr = 1 时,使用 images/illustration-small.png 这张图
  • 当屏幕的 dpr = 2 时,使用 images/illustration-big.png 这张图
  • 如果不支持 srcset 语法,src='illustration-small.png' 将会是最终的兜底方案

方案五:srcset 属性配合 sizes 属性 w 宽度描述符

上面 1x,2x 的写法比较容易接受易于理解。

但是,上述 3 种方案都存在统一的问题,只考虑了 DPR,但是忽略了响应性布局的复杂性与屏幕的多样性

因此,规范还推出了一种方案 -- srcset 属性配合 sizes 属性 w 宽度描述符

srcset 属性还有一个 w 宽度描述符,配合 sizes 属性一起使用,可以覆盖更多的面。

sizes 属性怎么理解呢?它定义图像元素在不同的视口宽度时,可能的大小值。

以下面这段代码为例子:

<img 
        sizes = “(min-width: 600px) 600px, 300px" 
        src = "photo.png" 
        srcset = “[email protected] 300w,
                       [email protected] 600w,
                       [email protected] 1200w,
>

解析一下:

sizes = “(min-width: 600px) 600px, 300px" 的意思是:

  1. 如果屏幕当前的 CSS 像素宽度大于或者等于 600px,则图片的 CSS 宽度为 600px
  2. 反之,则图片的 CSS 宽度为 300px

也就是 sizes 属性声明了在不同宽度下图片的 CSS 宽度表现。这里可以理解为,大屏幕下图片宽度为 600px,小屏幕下图片宽度为 300px。

需要注意的是,这里大屏、小屏下图片具体的宽度表现,还是需要借助媒体查询代码,经由 CSS 实现的

srcset = “[email protected] 300w, [email protected] 600w, [email protected] 1200w 里面的 300w,600w,900w 叫宽度描述符。

那么,怎么确定当前场景会选取哪张图片呢?

当前屏幕 dpr = 2 ,CSS 宽度为 375px

当前屏幕 CSS 宽度为 375px,则图片 CSS 宽度为 300px。分别用上述 3 个宽度描述符的数值除以 300。

  1. 300 / 300 = 1
  2. 600 / 300 = 2
  3. 1200 / 300 = 4

上面计算得到的 1、 2、 4 即是算出的有效的像素密度,换算成和 x 描述符等价的值 。这里 600w 算出的 2 即满足 dpr = 2 的情况,选择此张图。

当前屏幕 dpr = 3 ,CSS 宽度为 414px

当前屏幕 CSS 宽度为 414px,则图片 CSS 宽度仍为 300px。再计算一次:

  1. 300 / 300 = 1
  2. 600 / 300 = 2
  3. 1200 / 300 = 4

因为 dpr = 3,2 已经不满足了,则此时会选择 1200w 这张图。

当前屏幕 dpr = 1 ,CSS 宽度为 1920px

当前屏幕 CSS 宽度为 1920px,则图片 CSS 宽度变为了 600px。再计算一次:

  1. 300 / 600 = .5
  2. 600 / 600 = 1
  3. 1200 / 600 = 2

因为 dpr = 1,所以此时会选择 600w 对应的图片。

具体的可以试下这个 Demo:CodePen Demo -- srcset属性配合w宽度描述符配合sizes属性

此方案的意义在于考虑到了响应性布局的复杂性与屏幕的多样性,利用上述规则,可以一次适配 PC 端大屏幕和移动端高清屏,一箭多雕。

嗯,总结一下,在实现响应式图像时,我们同时使用 srcsetsizes 属性。它们的作用是:

  • srcset:定义多个不同宽度的图像源,让浏览器在 HTML 解析期间选择最合适的图像源
  • sizes:定义图像元素在不同的视口宽度时,可能的大小值

有了这些属性后,浏览器就会根据 srcset/size 来创建一个分辨率切换器的响应式图片,可以在不同的分辨率的情况下,提供相同尺寸的图像,或者在不同的视图大小的情况下,提供不同尺寸大小的图像。

本章节一共列举了 5 种实现响应式图片,适配不同屏幕大小,不同 DPR 的方式,它们分别是:

  1. 无脑多倍图的方式
  2. DRP 媒体查询
  3. CSS Background 中的使用 image-set
  4. srcset 配合 1x 2x 像素密度描述符
  5. srcset 属性配合 sizes 属性 w 宽度描述符

合理使用它们,可以有效的为不同屏幕,提供最为恰当的图片资源,在保证用户体验的同时,尽可能节省带宽。

它们各有优缺点,可以根据自己实际的业务场景,选取合适相对成本最低的方案,并且适当的配合 Autoprefixer 以及一些 PostCSS 等工具,简化代码量。

当然,本文只是现代图片性能优化及体验优化指南的第二篇,后续将给大家带来图片在:

  • 图片的宽高比、裁剪与缩放展示
  • 懒加载/异步图像解码方案
  • 可访问性以及图片资源的容错及错误处理

等相关知识的介绍,感兴趣的可以提前关注。

OK,本文到此结束,希望本文对你有所帮助 😃

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

想 Get 到最有意思的 CSS 资讯,千万不要错过我的 iCSS 公众号 😄 :

image

如果觉得文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK