介绍基于 SVG 的图像加载技术
从图像中生成的 SVG 可以作为占位图哦~
本文讨论如下内容:
占位图技术总览
基于 SVG 的占位图
自动化实现
现有占位图技术
在进行图像的懒加载时考虑使用怎样的占位图来渲染是一个很好的想法, 这对用户的感知体验有较大的影响以前常用的占位图方法如下:
给图像预留空间
在响应式设计的世界中, 这种方法避免了凭空出现的内容区域, 不过从用户体验的角度来看这种布局的变化是不好的, 对于性能来说也是如此: 浏览器每次获取图像的尺寸后都要被迫重新计算布局
占位图
假如要显示一个用户头像, 会先显示一个人物轮廓作为背景, 当加载时显示这个图案, 这种通常都是矢量图, 尺寸较小且易于嵌入
纯色
选择图像的主色调作为占位图的背景颜色, 这个颜色是基于所加载图像的, 并且从纯色到加载后的图像有一个平滑的过渡
模糊图
先使用一个小尺寸的模糊图像渲染, 然后加载完整图像, 初始的图像不论在像素 (px) 还是尺寸 (kB) 上都是最小的
使用 SVG 作为占位图
SVG 是矢量图的一种理想选择, 大多数情况下我们需要加载的是位图, 那么问题就变成了如何矢量化一个图像, 常用的方案是矢量化边形状和区域
边 - Edges
使用这篇文章中的方法检测图像中的边并创建路径动画如下面这个例子, 检测出边后创建了一个绘制的动画效果
形状 - Shapes
同样可以使用 SVG 的形状进行绘制, 这样一定程度上可以矢量化位图来创建占位图
下面这个例子是使用三角形的一个尝试, 可以看看作者在 CSSConf 和 Render Conf 的分享
上面这个 codepe 是使用 245 个三角形融合的一个 SVG 占位图三角形是使用基于 Delaunay 三角分解的 polyserver 生成的预料之中的是, 使用的 SVG 三角形越多文件尺寸越大
Primitive 与 SQIP
Tobias Baldauf 在低质量占位图 (Low-Quality Image Placeholder) 技术的基础上结合 SVG 做出了 SQIP 项目, 在了解 SQIP 前可以先看看 Primitive,SQIP 就是基于它的项目
Primitive 是个很棒的项目建议你了解下, 它将位图转换成了一个由多个重叠形状融合的 SVG 小尺寸的特点使其适应嵌入到页面中, 并且减少一次 (请求) 往返对于初始的 html 有效载荷是很有意义的
Primitive 使用三角形矩形与圆形等形状来生成图像, 执行过程的每一步都会添加一个图形, 结果图看起来很接近原始图, 不过若输出为 SVG 的话意味着输出的代码量会变大
为了便于理解 Primitive 的工作方式, 展示一下执行结果, 使用 10 与 100 个图形来生成 SVG:
可以看出, 当使用 10 个形状来构成图像时就可以看出原始图像的模样来在占位图的上下文中可以使用 SVG 作为占位图实际上 10 个形状的 SVG 代码量很小, 也就 1030 字节, 在使用 SVGO 输出后可以压缩到~ 640 字节
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024"><path fill="#817c70" d="M0 0h1024v1024H0z"/><g fill-opacity=".502"><path fill="#03020f" d="M178 994l580 92L402-62"/><path fill="#f2e2ba" d="M638 894L614 6l472 440"/><path fill="#fff8be" d="M-62 854h300L138-62"/><path fill="#76c2d9" d="M410-62L154 530-62 38"/><path fill="#62b4cf" d="M1086-2L498-30l484 508"/><path fill="#010412" d="M430-2l196 52-76 356"/><path fill="#eb7d3f" d="M598 594l488-32-308 520"/><path fill="#080a18" d="M198 418l32 304 116-448"/><path fill="#3f201d" d="M1086 1062l-344-52 248-148"/><path fill="#ebd29f" d="M630 658l-60-372 516 320"/></g></svg>
使用 100 个形状生成的图像就大一些了, 经过 SVGO 压缩后大概~ 5kB(压缩前 8kB), 在依然较小的 HTML payload 下保持了较高等级的细节, 使用三角形数量的多少基于取决于图像的类型 (对比度颜色数量复杂度) 与细节的等级
也可以创建一个类似 cpeg-dssim 的脚本来调整形状的数量使其达到一个结构相似度阈值(或者最坏情况下的最大形状数)
输出的 SVG 也可以作为背景图由于可限制尺寸与矢量化的特点也很适合作为首图 (hero image) 与大背景图
- SQIP
- Tobias:
- SQIP is an attempt to find a balance between these two extremes: it makes use of Primitive to generate a SVG consisting of several simple shapes that approximate the main features visible inside the image, optimizes the SVG using SVGO and adds a Gaussian Blur filter to it. This produces a SVG placeholder which weighs in at only ~8001000 bytes, looks smooth on all screens and provides an visual cue of image contents to come.
使用这个工具生成的结果图有点像在一个小尺寸占位图上使用模糊技术后的效果, 不同点在于前者不是位图图像(比如 JPG 或 webP), 而是 SVG
若在一个原始图像上执行 SQIP 会得到如下结果:
输出的 SVG 大小为~ 900 字节, 看一下代码会发现在形状上应用了 feGaussianBlur 滤镜:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000"><filter id="b"><feGaussianBlur stdDeviation="12" /></filter><path fill="#817c70" d="M0 0h2000v2000H0z"/><g filter="url(#b)" transform="translate(4 4) scale(7.8125)" fill-opacity=".5"><ellipse fill="#000210" rx="1" ry="1" transform="matrix(50.41098 -3.7951 11.14787 148.07886 107 194.6)"/><ellipse fill="#eee3bb" rx="1" ry="1" transform="matrix(-56.38179 17.684 -24.48514 -78.06584 205 110.1)"/><ellipse fill="#fff4bd" rx="1" ry="1" transform="matrix(35.40604 -5.49219 14.85017 95.73337 16.4 123.6)"/><ellipse fill="#79c7db" cx="21" cy="39" rx="65" ry="65"/><ellipse fill="#0c1320" cx="117" cy="38" rx="34" ry="47"/><ellipse fill="#5cb0cd" rx="1" ry="1" transform="matrix(-39.46201 77.24476 -54.56092 -27.87353 219.2 7.9)"/><path fill="#e57339" d="M271 159l-123-16 43 128z"/><ellipse fill="#47332f" cx="214" cy="237" rx="242" ry="19"/></g></svg>
- Using SVG as placeholdersMore Image Loading Techniques - JMPerez Blog
- fogleman/primitive: Reproducing images with geometric primitives.
- SQIP
来源: https://juejin.im/entry/5a953c075188252478691dc4