前端图片适配不同屏幕方案

预备知识:

设备独立像素,以下图的iphone12 Pro为例,390*844表示的就是设备独立像素(DIP),也可以理解为CSS像素
在这里插入图片描述

物理像素(设备像素),就是屏幕的分辨率,显示屏就是由一个个物理像素点组成的;
DPR(Device Pixel Ratio) 设备像素比,DPR = 物理像素 / 设备独立像素

在同样的css像素大小下,屏幕有不同的dpr,同样大小的图片渲染出来的效果会不一样;因此,为了在不同的 DPR 屏幕下,让图片看起来都不失真,我们需要为不同 DPR 的图片,提供不同大小的图片。有以下几个方案

方案一:媒体查询
通过相应的媒体查询,得知当前的设备的 DPR 值,使用对应的图片

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

缺点:

  • 可能存在一些介于 1和2,2和3 之间的 DPR 值,匹配不到对应的
  • 注意:
    需要注意语法需要的兼容性,需要添加前缀,譬如 -webkit-min-device-pixel-ratio,可以由 autoprefixer 插件解决

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

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

缺点:

  • 和方案一一样

方案三:srcset 配合像素密度描述符
img标签的srcset属性 可以根据不同的 dpr 拉取对应尺寸的图片

 <div class='image'>
    <img src='[email protected]'
        srcset='[email protected] 2x,
                [email protected] 3x'
    >
 div>

上面 srcset 里的 2x,3x 表示 像素密度描述符,当屏幕的 dpr = 2 时,使用 [email protected] 这张图,以此类推
缺点:

  • 和方案一一样

方案四:srcset 属性配合 sizes 属性 w 宽度描述符
上述 3 种方案都存在统一的问题,只考虑了 DPR,但是忽略了响应性布局的复杂性与屏幕的多样性;
srcset 属性还有一个 w 宽度描述符,配合 sizes 属性一起使用,可以覆盖更多的面;
sizes定义图像元素在不同的视口宽度时,可能的大小值;

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

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

  • 如果屏幕当前的 CSS 像素宽度大于或者等于 600px,则图片的 CSS 宽度为 600px
  • 反之,则图片的 CSS 宽度为 300px
    srcset = “[email protected] 300w, [email protected] 600w, [email protected] 1200w 里面的 300w,600w,900w 叫宽度描述符。

示例:
当前屏幕 dpr = 2 ,CSS 宽度为 375px。
当前屏幕 CSS 宽度为 375px,则图片 CSS 宽度为 300px(因为sizes定义了最小宽度,屏幕375px小于600px,所以图片的CSS宽度为300px)。分别用上述 3 个宽度描述符的数值除以 300。

  • 300 / 300 = 1
  • 600 / 300 = 2
  • 1200 / 300 = 4
    上面计算得到的 1、 2、 4 即是算出的有效的像素密度,换算成和 x 描述符等价的值 。这里 600w 算出的 2 即满足 dpr = 2 的情况,匹配到[email protected]这张图。

示例:
当前屏幕 dpr = 3 ,CSS 宽度为 414px。
当前屏幕 CSS 宽度为 414px,则图片 CSS 宽度仍为 300px

  • 300 / 300 = 1
  • 600 / 300 = 2
  • 1200 / 300 = 4
    dpr = 3,2 不满足,因此匹配到 1200w 这张图。

JavaScript 方案实现图片的懒加载

通过 JavaScript 实现的懒加载,主要是两种方式:

  • 监听 onscroll 事件,通过 getBoundingClientRect API 获取元素图片距离视口顶部的距离,配合当前可视区域的位置实现图片的懒加载
  • 通过 HTML5 的 IntersectionObserver API,Intersection Observer(交叉观察器) 配合监听元素的 isIntersecting 属性,判断元素是否在可视区内,能够实现比监听 onscroll 性能更佳的图片懒加载方案
    还有一种是类似于懒加载的方式,类似于虚拟列表
  • 使用 content-visibility: auto 实现图片内容的延迟渲染
<template>
  <div class="card">
    <div class="img-container">
      <img class="img" :src="props.url" />
    div>
    <div class="title">{{ props.title }}div>
    <div class="area">{{ props.area }}div>
    <div class="collect">{{ props.collect }}人想要div>
    <div class="price"><span class="amount">{{ props.price }}span>
    div>
  div>
template>

<style>
.card {
  content-visibility: auto;
}
style>

不在可视区域内的内容,一开始是没有被渲染的,在每次滚动的过程中,才逐渐渲染,以此来提升性能;虽然当前页面可视区域外的内容未被渲染,但是图片资源的 HTTP/HTTPS 请求,依然会在页面一开始被触发;因此严格来讲它并不是一个懒加载的方式;

你可能感兴趣的:(前端,图像处理)