一次搞定Web图片尺寸和分辨率问题

745 阅读8分钟

一次搞定Web图片尺寸和分辨率问题

前言

你是否遇到过这些Web图片的开发问题:

  • 图片的尺寸不符合预期,不知道怎样去调整它
  • 图片在某些设备上的清晰度太低,涉及到设备像素密度、分辨率、PPI、DPR、物理像素、逻辑像素一大堆概念实在太复杂难以搞明白
  • 图片响应式的响应式切换不符合预期,不知道该怎样调整

这些问题归根结底其实就是: 图片的尺寸响应式和分辨率切换, 这也正是本文要说清楚的问题!

好了,现在让我们开始吧! ^_T

图片

在开始之前, 我想我们应该先讨论一下什么是图片,这非常重要, 对于理解下面的内容!!!!

其实图片只是一个信息的载体, 它传达的是一种视觉信息, 因此作为一个信息载体, 它自身是由一个一个有颜色的像素块组成的,而不同的图片他们包含的像素块的颜色个数不同的,因此传达的视觉信息也就是不同的.

因此,一个图片由组成它的一个一个的像素所决定, 当像素点越来越多,那么图片也就会越来越清楚, 传达的信息也更加清晰,反之则模糊. 当然, 除了图像自身决定着它蕴藏信息的多少,具体设备能展示多少像素点也决定着图片是否清晰!!!

而浏览器在渲染图片的时候可以这样理解, 浏览器会读取到图片的每一个像素点, 然后根据我们当前屏幕能展示多少像素点(设备像素比)来决定我们具体怎样更好的展示这个图片,让它很兼容的适配它所在的盒子!!

而在这个过程中, 我们是可以做一些操作的,比如控制两个方向:

  1. 图片渲染的尺寸 => 操作盒子
  2. 图片的清晰度 => 控制清晰度

让我们带着对图片的理解,看看如何控制一个图片的尺寸(这没那么简单!)!

图片尺寸

注: 请仔细观察图片的宽高变化,这对理解他们的关系很重要!

我们如何把一个图片URL或者图像数据展示在浏览器中?浏览器提供给了我们img标签和对应的接口,我们通常只需要:

<img src="elva-fairy-640w.jpg" />

image.png

很神奇,这样我们就可以直接在浏览器中看到我们的图片了,我们甚至没有给它宽度和高度,它就已经可以自动的显示出来,现在我们来对它做一点调整!

这里图片宽高为640 * 427 (这是图片原本展示的宽高)

让它最终展示的宽高为200 * 200

如何实现这个效果呢?

直接修改img标签的宽高:

// css: 
img {
    height: 200px;
    width: 200px;
}

外层嵌套一个div,然后img的宽高设置为100%

<div>
<img src="elva-fairy-640w.jpg" />
</div>

<style>
    div {
        width: 200px;
        height: 200px;
    }
    
    img {
        width: 100%;
        height: 100%;
    }
</style>

我们代码的最终效果如下:

image.png

image.png

可见, 当我们通过css调整图片的渲染的宽高后, 图片会被浏览器自动的进行缩放!并且,浏览器的自动缩放还存在于我们设备尺寸发生变化时!而我们下面要介绍的正是解决不同设备尺寸下, 如何加载一张视觉信息展示最好的图片!

根据不同设备尺寸响应的图片

要根据不同的设备宽度来响应不同的图片时, 这时就要引入img标签的属性srcset 和 sizes——来提供额外的资源图像和提示,帮助浏览器选择最合适的资源。

<img
  srcset="elva-fairy-480w.jpg 480w, elva-fairy-800w.jpg 800w"
  sizes="(max-width: 600px) 480px,
         800px"
  src="elva-fairy-800w.jpg"
  />

具体的属性作用参考MDN这里不再赘述,我们现在只需要知道通过这两个属性,我们可以告诉浏览器我们希望在屏幕宽度小于600px时使用elva-fairy-480w.jpg这张图片即可,而这张 图片自身的宽高是符合我们的预期的!!

这就给我们在不同的屏幕尺寸大小下展示完全不同的图片!!

内容响应式图片

除了设定根据页面尺寸大小切换图片,包裹着图片自身的img标签(不清楚看上面的图)也是可以响应式的,我们希望可以控制图片自身在这个盒子中的位置、伸缩与否等等来让图片更好的填充img标签!!!!

这里就需要引出我们要介绍的两个css属性:

object-fit CSS 属性指定可替换元素的内容应该如何适应到其使用高度和宽度确定的框。

效果如下:

image.png

object-position 属性来切换被替换元素的内容对象在元素框内的对齐方式。

效果如下:

image.png

注: 背景图片类比: background-size & background-position

图片的清晰度

图片的清晰度, 这里我们定义它表示的是: 最终展示出来的图片所覆盖的像素点的个数, 而最终展示的个数我们上面提到过, 它其实取决于浏览器根据实际物理屏幕像素点个数图片自身的像素点个数二者有关联!

所以一个图片的呈现其实要经过蛮多的步骤的,我们大致可以用下图来模拟它:

image.png

这里重点在于 像素点的对应, 一个一个被解析后的图片二进制数据流变成了一个一个的像素点被这样子对应到了屏幕上的像素点,而只要对应到屏幕上的像素点个数 >= 浏览器解析后的图片的一个一个像素点, 那么这个时候我们人眼就会觉得清晰!!, 并且随着最终我们展示到屏幕上的像素点个数增大,那么显然,我们就会觉得这个图片会越来越清晰!!!

切换不同分辨率图片

这里同样要引入上面提到过的srcset属性,代码如下:

<img
  srcset="elva-fairy-320w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-640w.jpg 2x"
  src="elva-fairy-640w.jpg"
  sizes="(max-width: 600px) 480px,
     800px"
  alt="Elva dressed as a fairy" />
 <img
  srcset="elva-fairy-640w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-320w.jpg 2x"
  src="elva-fairy-640w.jpg"
  sizes="(max-width: 600px) 480px,
     800px"
  alt="Elva dressed as a fairy" />
  
  img {
     width: 320px;
  }

这里我们调换了在设备像素比为1时的顺序,也就是浏览器解析图片的像素点个数,显然2大于1的个数,所以最终我们可以很清晰的看到,2的清晰度要更高!!!

image.png

总结和最佳实践

按照以下步骤来:

确认好你想要响应式的是图片的什么?

  1. 图片的尺寸大小

    1. 直接使用srcset + sizes属性实现, easy!
    2. picture标签+ source标签+img实现, easy!
  2. 图片的分辨率

    1. srcset配置好对应的像素密度参数即可实现, easy!
  3. 图片在容器中展示的大小比例

    1. 修改图片内容元素在img标签中的展示宽高效果 =》直接修改img标签的宽高以及图片内容益处的策略,easy!

    2. 修改容纳img标签的盒子, 定义img元素在盒子中的表现形式即可,easy!

      1. object-fit
      2. object-position
      3. background-position
      4. background-size
    3. 修改图片方向、缩放算法等,complex(下面说......)

其它图片操作

调整浏览器渲染的图片的预设方向——image-orientation

属性值如下:

  • from-image: 根据图片的EXIF数据来修正图片的旋转方向
  • 一个角度大小: 图片的旋转值(四舍五入到90deg的整数倍)
  • flig: 图片水平翻转

调整浏览器对图片的缩放操作——image-rendering

触发条件:

每一个图片资源都会有它默认的尺寸,但是开发者通常会指定一个图片的width和height,一旦二者不匹配浏览器会自动的进行缩放操作,此时,我们可以通过image-rendering属性来操作缩放.

属性值如下:

  • auto: 默认缩放规则
  • smooth: 应使用能最大化图像客观观感的算法来缩放图像
  • high-quality: 除了客观的感官外,高质量的缩放优先
  • crisp-edges: 必须使用可有效保留对比度和图像中的边缘的算法来对图像进行缩放,并且,该算法既不会平滑颜色,又不会在处理过程中为图像引入模糊。合适的算法包括最近邻居nearest-neighbor)算法和其他非平滑缩放算法,比如 2×SaI 和 hqx-* 系列算法。此属性值适用于像素艺术作品,例如一些网页游戏中的图像。
  • pixelated: 放大图像时,使用最近邻居算法,因此,图像看着像是由大块像素组成的。缩小图像时,算法与 auto 相同。

auto、pixelated、crisp-edges区别:

image.png

设置图像的分辨率——image-resolution

注: 先声明, 这个属性是一个实验性质的,不要在production中使用

在默认情况下, 浏览器会根据图片的naturalHeight和naturalWidth来对应着去渲染图片到页面上,但是我们可以通过这个属性来调整物理像素和css像素px之间的对应关系

  • from-image: 默认一句图像的分辨率
  • 具体的值: 指定按照多少分辨率对应
  • 组合起来: 默认按照图像,没有再按照具体的来对应