拖动图片或点击选择
PNG, JPEG, WebP, GIF, BMP, AVIF
工作原理
占位图就是在图片下载期间代替它的内容。它有两个不同的作用:预留图片将要占据的确切空间,使图片出现时周围的文字不会跳动;以及显示与最终内容相似的画面,让等待的感觉比面对一个灰色矩形要短。
解决方案分为三类。紧凑哈希(BlurHash 和 ThumbHash)把图片压缩成极短的文本字符串,短到可以和记录的其余字段一起存进数据库的一列;浏览器解码后绘制出模糊图。data URI(LQIP 缩略图和 SVG)把已编码的图片直接放进 HTML 或 CSS,因此完全不需要 JavaScript。而纯色是所有占位方案中最省的:七个字符。
选哪一种取决于 HTML 从何而来。如果图片来自数据库、而且要成百上千地列出,那么按记录计算哈希最轻。如果你生成静态页面,或使用已经支持占位图的框架,data URI 可以省去添加解码代码。你在这里看到的所有数值都在你的浏览器中计算:图片不会上传到任何服务器。
示例
blurhash 4 × 3LGHC162?|cKNqSWDjtaghVfjfQfjBlurHash 的长度只取决于分量数量,与图片的尺寸和内容无关:4 × 3 始终是 28 个字符,3 × 3 是 22 个,5 × 4 是 44 个。thumbhash3wcKNZpwh3eAiIh3iHiIiHCAB/eH一个 ThumbHash 占 17 到 25 字节,即 Base64 下的 24 到 36 个字符。确切大小取决于图片的宽高比以及是否带透明度,因为该格式还会编码 alpha 通道。lqip 24 px webpdata:image/webp;base64,UklGRi…宽 24 px 的 WebP 缩略图通常小于 1 KB。它内嵌在 HTML 中,不会产生额外请求,但会让文档变大,而文档不会被单独缓存。使用场景
- 把 BlurHash 或 ThumbHash 存进图片表,让列表或无限滚动的信息流从第一刻起就有内容可显示。
- 当图片不是静态导入时,填写 next/image 的 blurDataURL 属性或 NgOptimizedImage 的 placeholder。
- 把占位图与 width、height 属性结合使用,避免产品卡片或文章卡片出现布局偏移(CLS)。
- 在无法运行解码 JavaScript 的静态 HTML、邮件或模板中嵌入占位图。
- 在网页和移动应用中复用同一个 BlurHash,移动端有 Swift、Kotlin 和 Flutter 的解码器。
- 当字节预算连一张缩略图都容不下时,用平均颜色作为容器背景。
常见问题
选 BlurHash 还是 ThumbHash?
ThumbHash 用更少的字节更忠实地还原图片,保留透明度并记录宽高比,因此你甚至不需要知道原始尺寸就能绘制它。BlurHash 出现得更早、精度较低,但在更多平台和语言上都有实现。如果从零开始,选 ThumbHash;如果你的技术栈里已经有 BlurHash 解码器,就没必要迁移。
这样能改善 LCP 吗?
不会直接改善。占位图提升的是速度的主观感受,配合 width 和 height 还能消除布局偏移,但 LCP 指标仍然以真实图片绘制完成的时刻来计算。更进一步:如果主图就是 LCP 元素,不要给它加 loading="lazy",也不要把它藏在占位图后面延迟加载;应该用 fetchpriority="high" 标记它,让浏览器更早发起请求。占位图是给首屏之外的图片用的。
BlurHash 该用多少个分量?
横向图片用 4 × 3 效果不错,竖向图片用 3 × 4。每增加一个分量会多出两个字符和一点细节,但超过六或七之后,肉眼就分辨不出差别了,因为结果本来就是模糊显示的。
选哈希还是 data URI?
哈希每张图片只占几十个字节,在同一页面有大量图片时非常合适,但需要客户端代码来解码。data URI 什么都不需要,不过体积要大十到五十倍,而且随 HTML 一起传输,而 HTML 不会被单独缓存。图片不多且是重点展示时,用 data URI 更合适;列表很长时,用哈希。
为什么要用 SVG,而不是直接用缩略图?
因为模糊是浏览器在绘制 SVG 时施加的。这样你可以从更小的缩略图出发,放大时也不会出现像素块,而且在任何尺寸下都同样平滑。SVG 还会把 alpha 固定为不透明,以免模糊让边缘变透明。
占位图有大小限制吗?
取决于所用的工具。当占位图的 data URI 超过 4000 个字符时,Angular 的 NgOptimizedImage 会在控制台发出警告,因为从那时起 HTML 的体积代价开始超过收益。这是一个不错的通用参考:如果你的缩略图超过这个数值,就降低宽度或质量。