渐进式图像加载 - 模糊占位符图像(如 Unsplash)
Unsplash 是我最喜欢的图片网站,不仅因为它有大量免费图片,还因为它的用户体验非常好。Unsplash 开始使用 BlurHash 来提供 渐进式图片加载 体验已经有一段时间了。
概念
渐进式图像加载
渐进式图像加载 可带来更好的用户体验。但什么是渐进式图像加载?
无需等待最终图像渲染完成,先使用低质量图像作为占位符 (LQIP),加载完成后再切换到原始图像。
发生了什么?
- 使用特定
aspect-ratio
渲染元素(例如div
),通常与原始图像相同 - 先渲染 低质量图像
- 当此元素 在视口中时,触发加载原始图像
- 原始图像加载完成后,在低质量图像上渲染原始图像,然后在背景上 隐藏/删除低质量图像
以下是一个例子:
占位图 vs 原始图
⬅️ 这个 8×6 像素的图像可以放大多次(例如,在我的屏幕上为 865×649 像素),而不会增加明显的噪音。
Unsplash 是怎么做的
- 使用 XHR 获取列表数据
- 从列表项的
blur_hash
字段解码 BlurHash - 从使用解码的 BlurHash 数据绘制的画布生成 8 x 8 像素
image/bmp
图像,并将其渲染为图像占位符 - 在加载时渲染原始图像
为什么用 BMP 呢?
请查看 图片大小对比.
此外,渲染小尺寸图像比绘制画布消耗更少的 CPU 和内存。
如何生成占位图?
Photoshop 是处理滤镜效果(例如高斯模糊)的绝佳工具,但对于大多数用户来说太复杂了。
因此我创建了一个 Web 应用程序 (Image Blurrer) 来生成模糊的占位符图像。支持 4 种类型的输出图像:
对比
图像质量
使用我的 Image Blurrer,在使用 StackBlur 生成模糊图像时,可以自定义模糊半径。在我的个人使用和测试中,StackBlur 是我的最爱,因为它的模糊半径灵活。
画布大小 | 模糊半径 |
---|---|
32 px | 2 px |
BlurHash 在大多数情况下是一个不错的选择(可以从 Unsplash 的经验中证明),但是在某些情况下它会将原始图像的暗区渲染得太暗。
例如:
原始图片 | BlurHash |
---|---|
https://r2-assets.thelynan.com/uPic/P1010249.jpg | UcF~mn?b00D$~q-:IUM{?c%3M{RjWBWBt7xu |
图片尺寸对比
测试图片: https://r2-assets.thelynan.com/uPic/progress-image-loading-test-img.jpg
我在测试结果中突出显示了最小尺寸。在我的测试中,当画布宽度低于 10px 时,image/bmp
最小,然后在 12px - 22px 之间,image/png
占据主导地位,之后 image/jpeg
最小。
width(px) | jpeg | png | bmp |
---|---|---|---|
4 | 816 B | 132 B | 90 B |
6 | 828 B | 168 B | 135 B |
8 | 825 B | 222 B | 198 B |
10 | 846 B | 279 B | 279 B |
12 | 867 B | 366 B | 378 B |
14 | 885 B | 432 B | 495 B |
16 | 882 B | 546 B | 630 B |
18 | 936 B | 618 B | 783 B |
20 | 954 B | 768 B | 954 B |
22 | 942 B | 855 B | 1.1 KB |
24 | 1.0 KB | 1.0 KB | 1.3 KB |
26 | 1.0 KB | 1.1 KB | 1.5 KB |
28 | 1.1 KB | 1.3 KB | 1.8 KB |
30 | 1.1 KB | 1.4 KB | 2.0 KB |
32 | 1.1 KB | 1.6 KB | 2.3 KB |
实际上,大多数浏览器不支持通过 canvas.toDataURL 直接生成 image/bmp
,如果指定的类型不受支持,则将使用 image/png
格式。
解决方案:
- canvs-to-bmp
- jimp 我的选择,因为我已经用它来生成 CSS 渐变,而且在我的实践中,jimp 生成尺寸较小的 bmp 图像文件。
1 | const img = await Jimp.read("./path/to/image.jpg"); |
感谢
渐进式图像加载 - 模糊占位符图像(如 Unsplash)