随着现在高分辨率显示器(2K,4K)的普及,以及移动设备上屏幕的ppi的提高,网页上提供高分辨率的图片显得越来越重要。
在用 Webpack 构建的项目中,常见的解决方式,就是提供一张高分辨率的图片,然后在编译时压缩生成对应的低分辨率的版本,这种方法处理较为简单,但是也有一些问题:图片压缩只能是固定的压缩比例;压缩质量不好控制;代码中使用的时候诸多不便;
而现在我们在设计的时候,一般都直接提供了 1x 2x 甚至是 3x 的图片素材,也就是说,压缩这一步骤已经没有太多的必要。
一开始的思路
所以一个简单的思路就是,按照 original.png
original@2x.png
这样的形式去命名图片,然后页面中去引用,低分辨率用 original.png
,高分辨率用 original@2x.png
。配合 file loader
,实现起来非常简单,require
1x 的图片,然后利用 copy-webpack-plugin
将2x的图片复制到相同的目录,最后需要用 2x 的图片的时候,直接替换文件路径就可以。
这种方法有一个问题,就是 2x 图片不好管理,因为需要与 1x 图片的名字前缀保持一致,也就无法对 1x 图片文件名进行 hash,对于缓存控制不太好。
于是我就想,能不能在 resolve 1x 图片的同时,将 2x 图片也一起 resolve 并且把 2x 图片的 resolve 结果也返回,这样在代码中就可以同时得到 1x 和 2x 图片的引用,可以自由使用和组合。
ideal-image-loader
找了一下,发现已经有 ideal-image-loader 这个开源的项目了,它的逻辑就是和我上面说的一样,配合 srcset,可以轻松的解决 2x 图片的问题。
import image from './abc.png';
/*
image:
{
x1: {
src: "",
},
x2: {
src: "",
},
}
*/
const srcset = `${image.x1.src} x1, ${image.x2.src} x2`
<img srcset={srcset} />
这样就实现了自动的图片 2x 控制。对于开发者来说也是无感的,非常方便。
后续的一些问题
-
由于 ideal-image-loader 和 file-loader 的返回格式不一样,导致有些想要直接引用图片的地方不能正常工作了 常见的就是
.a { background: url(./assets/example.png); }
这些背景图片直接写在 css 中,不需要使用 2x 图片,因此只要 file-loader 就可以了。
这时有两种方案可以选择:将这些图片放到特定的文件夹,调整 rule 的include 和 exclude;或者可以通过 rule 的 issuer,所有在 css 中引入的图片,都使用 file-loader 加载。