Skip to content

如何保持图片清晰度 ​

日常开发中,我们通常会使用一张比较大的图片来作为背景图,或者使用一张比较大的图片来作为图片的缩略图,这样可以保证图片在不同分辨率下都能保持清晰度。

但是这样的问题在于,当分辨率比较小时。根本不需要这么大的图片,浪费带宽并且影响性能。

我们可以让UI同学提供不同分辨率的图片,然后根据屏幕的分辨率来选择不同分辨率的图片来进行展示。这样可以保证图片在不同分辨率下都能保持清晰度,并且不会浪费带宽。

解决方案 ​

我们以 一张 width 500px的图片为例,我们可能会写出如下代码

vue
<template>
  <div>
    <h1> Image </h1>
    <div class="img-container" />
  </div>
</template>

<style>
.img-container {
  width: 500px;
  margin: a auto;
  height: 300px;
  background: url('./image/spring@500') no-repeat center center;
}
</style>

在浏览器中运行上述代码,我们发现图像并不清晰,元素宽度500px,图片宽度500px,选择一张500宽度的图片有什么问题呢?为什么会模糊呢?

原因:我们没有考虑DPR(设备像素比),当浏览器在缩放时,以以DPR等于2为例,500宽度 的图片会被拉伸到1000px宽度,那自然就不清晰了。我们要保持图片清晰,那我们 background 中的 url的图片宽度就要大于等于元素的宽度乘以DPR。如下

css
/* DPR*宽度 */
background: url('./image/spring@[DPR*宽度]') no-repeat center center;

我们不可能每次手动修改,我们也不知道用户的DPR是多少,而且DPR也不是一个固定的值,可能是1.5,也可能是2.5,那么怎么办呢? 我们可以使用一个CSS属性 image-set 来解决这个问题。我们可以使用 image-set 来根据DPR来选择不同分辨率的图片。如下

css
.img-container {
  width: 500px;
  margin: a auto;
  height: 300px;
  background: image-set(
    url('./image/spring@1x') 1x,
    url('./image/spring@2x') 2x,
    url('./image/spring@3x') 3x
  ) no-repeat center center;
}

这样就可以根据DPR来选择不同分辨率的图片了。我们可以使用 1x,2x,3x 来表示不同分辨率的图片。浏览器会根据DPR来选择不同分辨率的图片来进行展示。

在背景中我们可以他通过image-set解决这个问题,但是在img标签中我们就不能使用 image-set 了,我们可以使用 srcset 来解决这个问题。如下

vue
<template>
  <div>
    <h1> Image </h1>
    <img
     src="./image/spring@1x" 
     srcset="./image/spring@2x 2x, ./image/spring@3x 3x" />
  </div>
</template>

但是上述方案都存在问题:

  1. image-set 兼容性 有问题,只支持部分浏览器
  2. 图片应该使用哪一张不仅仅取决于DPR,还取决于img的宽度,img的宽度可能是500px,也可能是1000px,甚至可能是2000px,这样也会导致图片不清晰。

所以我们最终需要的图片width 和 DPR 都有关系。

有的时候,因为网页上的一些动画效果改变了图片宽度,尽管DPR没有变化,但图片也应该进行自动切换,遗憾的是img元素不像背景图那样在放大和缩小时候自动切换图片,它只会在初始渲染时选择一张图片。因此,我们只能借助js来解决这些问题。

我们以vue为例 实现一个 ScaleImaege 组件
全部代码参见:
https://github.com/pangqiang/vue3-start/blob/main/src/components/ScaleImage.vue

上次更新于: