Merge pull request #6397 from qhwdw/master

Translated by qhwdw
This commit is contained in:
qhwdw 2017-11-30 15:57:37 +08:00 committed by GitHub
commit 1363123ad9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 238 additions and 240 deletions

View File

@ -1,240 +0,0 @@
Translating by qhwdw
How to use SVG as a Placeholder, and Other Image Loading Techniques
============================================================
![](https://cdn-images-1.medium.com/max/1563/0*zJGl1vKLttcJGIL4.jpg)
Generating SVGs from images can be used for placeholders. Keep reading!
Im passionate about image performance optimisation and making images load fast on the web. One of the most interesting areas of exploration is placeholders: what to show when the image hasnt loaded yet.
During the last days I have come across some loading techniques that use SVG, and I would like to describe them in this post.
In this post we will go through these topics:
* Overview of different types of placeholders
* SVG-based placeholders (edges, shapes and silhouettes)
* Automating the process.
### Overview of different types of placeholders
In the past [I have written about placeholders and lazy-load of images][28], and also [talked about it][29]. When doing lazy-loading of images its a good idea to think about what to render as a placeholder, since it can have a big impact in users perceived performance. In the past I described several options:
![](https://cdn-images-1.medium.com/max/1563/0*jlMM144vAhH-0bEn.png)
Several strategies to fill the area of an image before it loads.
* Keeping the space empty for the image: In a world of responsive design, this prevents content from jumping around. Those layout changes are bad from a users experience point of view, but also for performance. The browser is forced to do layout re calculations every time it fetches the dimensions of an image, leaving space for it.
* Placeholder: Imagine that we are displaying a users profile image. We might want to display a silhouette in the background. This is shown while the main image is loaded, but also when that request failed or when the user didnt set any profile picture at all. These images are usually vector-based, and due to their small size are a good candidate to be inlined.
* Solid colour: Take a colour from the image and use it as the background colour for the placeholder. This can be the dominant colour, the most vibrant… The idea is that it is based on the image you are loading and should help making the transition between no image to image loaded smoother.
* Blurry image: Also called blur-up technique. You render a tiny version of the image and then transition to the full one. The initial image is tiny both in pixels and kBs. To remove artifacts the image is scaled up and blurred. I have written previously about this on [How Medium does progressive image loading][1], [Using WebP to create tiny preview images][2], and [More examples of Progressive Image Loading][3] .
Turns out there are many other variations and lots of smart people are developing other techniques to create placeholders.
One of them is having gradients instead of solid colours. The gradients can create a more accurate preview of the final image, with very little overhead (increase in payload).
![](https://cdn-images-1.medium.com/max/1250/0*ecPkBAl69ayvRctn.jpg)
Using gradients as backgrounds. Screenshot from Gradify, which is not online anymore. Code [on GitHub][4].
Another technique is using SVGs based on the image, which is getting some traction with recent experiments and hacks.
### SVG-based placeholders
We know SVGs are ideal for vector images. In most cases we want to load a bitmap one, so the question is how to vectorise an image. Some options are using edges, shapes and areas.
#### Edges
In [a previous post][30] I explained how to find out the edges of an image and create an animation. My initial goal was to try to draw regions, vectorising the image, but I didnt know how to do it. I realised that using the edges could also be innovative and I decided to animate them creating a “drawing” effect.
[Drawing images using edge detection and SVG animation
Back in the days SVG was barely used and supported. Some time after we started using them as an alternative to classic…medium.com][31][][32]
#### Shapes
SVG can also be used to draw areas from the image instead of edges/borders. In a way, we would vectorise a bitmap image to create a placeholder.
Back in the days I tried to do something similar with triangles. You can see the result in my talks [at CSSConf][33] and [Render Conf][34].
The codepen above is a proof of concept of a SVG-based placeholder composed of 245 triangles. The generation of the triangles is based on [Delaunay triangulation][35] using [Possans polyserver][36]. As expected, the more triangles the SVG uses, the bigger the file size.
#### Primitive and SQIP, a SVG-based LQIP technique
Tobias Baldauf has been working on another Low-Quality Image Placeholder technique using SVGs called [SQIP][37]. Before digging into SQIP itself I will give an overview of [Primitive][38], a library on which SQIP is based.
Primitive is quite fascinating and I definitely recommend you to check it out. It converts a bitmap image into a SVG composed of overlapping shapes. Its small size makes it suitable for inlining it straight into the page. One less roundtrip, and a meaningful placeholder within the initial HTML payload.
Primitive generates an image based on shapes like triangles, rectangles and circles (and a few others). In every step it adds a new one. The more steps, the resulting image looks closer to the original one. If your output is SVG it also means the size of the output code will be larger.
In order to understand how Primitive works, I ran it through a couple of images. I generated SVGs for the artwork using 10 shapes and 100 shapes:
** 此处有Canvas,请手动处理 **
![](https://cdn-images-1.medium.com/max/625/1*y4sr9twkh_WyZh6h0yH98Q.png)
![](https://cdn-images-1.medium.com/max/625/1*cqyhYnx83LYvhGdmg2dFDw.png)
![](https://cdn-images-1.medium.com/max/625/1*qQP5160gPKQdysh0gFnNfw.jpeg)
Processing [this picture][5] using Primitive, using [10 shapes][6] and [100 shapes][7].
![](https://cdn-images-1.medium.com/max/625/1*PWZLlC4lrLO4CVv1GwR7qA.png)
![](https://cdn-images-1.medium.com/max/625/1*khnga22ldJKOZ2z45Srh8A.png)
![](https://cdn-images-1.medium.com/max/625/1*N-20rR7YGFXiDSqIeIyOjA.jpeg)
Processing [this picture][8] using Primitive, using [10 shapes][9] and [100 shapes][10].
When using 10 shapes the images we start getting a grasp of the original image. In the context of image placeholders there is potential to use this SVG as the placeholder. Actually, the code for the SVG with 10 shapes is really small, around 1030 bytes, which goes down to ~640 bytes when passing the output through SVGO.
```
<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 92L40262"/><path fill=”#f2e2ba” d=”M638 894L614 6l472 440"/><path fill=”#fff8be” d=”M-62 854h300L13862"/><path fill=”#76c2d9" d=”M41062L154 53062 38"/><path fill=”#62b4cf” d=”M10862L49830l484 508"/><path fill=”#010412" d=”M4302l196 5276 356"/><path fill=”#eb7d3f” d=”M598 594l48832308 520"/><path fill=”#080a18" d=”M198 418l32 304 116448"/><path fill=”#3f201d” d=”M1086 1062l-34452 248148"/><path fill=”#ebd29f” d=”M630 658l-60372 516 320"/></g></svg>
```
The images generated with 100 shapes are larger, as expected, weighting ~5kB after SVGO (8kB before). They have a great level of detail with a still small payload. The decision of how many triangles to use will depend largely on the type of image (eg contrast, amount of colours, complexity) and level of detail.
It would be possible to create a script similar to [cpeg-dssim][39] that tweaks the amount of shapes used until a [structural similarity][40] threshold is met (or a maximum number of shapes in the worst case).
These resulting SVGs are great also to use as background images. Being size-constrained and vector-based they are a good candidate for hero images and large backgrounds that otherwise would show artifacts.
#### SQIP
In [Tobias own words][41]:
> SQIP is an attempt to find a balance between these two extremes: it makes use of [Primitive][42] to generate a SVG consisting of several simple shapes that approximate the main features visible inside the image, optimizes the SVG using [SVGO][43] 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.
The result is similar to using a tiny placeholder image for the blur-up technique (what [Medium][44] and [other sites][45] do). The difference is that instead of using a bitmap image, eg JPG or WebP, the placeholder is SVG.
If we run SQIP against the original images well get this:
![](https://cdn-images-1.medium.com/max/938/0*yUY1ZFP27vFYgj_o.png)
![](https://cdn-images-1.medium.com/max/938/0*DKoZP7DXFvUZJ34E.png)
The output images using SQIP for [the first picture][11] and [the second one][12].
The output SVG is ~900 bytes, and inspecting the code we can spot the `feGaussianBlur` filter applied to the group of shapes:
```
<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-12316 43 128z"/><ellipse fill="#47332f" cx="214" cy="237" rx="242" ry="19"/></g></svg>
```
SQIP can also output an image tag with the SVG contents Base 64 encoded:
```
<img width="640" height="640" src="example.jpg” alt="Add descriptive alt text" style="background-size: cover; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAw…<stripped base 64>…PjwvZz48L3N2Zz4=);">
```
#### Silhouettes
We just had a look at using SVGs for edges and primitive shapes. Another possibility is to vectorise the images “tracing” them. [Mikael Ainalem][47] shared [a codepen][48] a few days ago showing how to use a 2-colour silhouette as a placeholder. The result is really pretty:
![](https://cdn-images-1.medium.com/max/1250/1*r6HbVnBkISCQp_UVKjOJKQ.gif)
The SVGs in this case were hand drawn, but the technique quickly spawned integrations with tools to automate the process.
* [Gatsby][13], a static site generator using React supports these traced SVGs now. It uses [a JS PORT of potrace][14] to vectorise the images.
* [Craft 3 CMS][15], which also added support for silhouettes. It uses [a PHP port of potrace][16].
* [image-trace-loader][17], a Webpack loader that uses potrace to process the images.
Its also interesting to see a comparison of the output between Emils webpack loader (based on potrace) and Mikaels hand-drawn SVGs.
I assume the output generated by potrace is using the default options. However, its possible to tweak them. Check [the options for image-trace-loader][49], which are pretty much [the ones passed down to potrace][50].
### Summary
We have seen different tools and techniques to generate SVGs from images and use them as placeholders. The same way [WebP is a fantastic format for thumbnails][51], SVG is also an interesting format to use in placeholders. We can control the level of detail (and thus, size), its highly compressible and easy to manipulate with CSS and JS.
#### Extra Resources
This post made it to [the top of Hacker News][52]. Im very grateful for that, and for all the links to other resources that have been shared in the comments on that page. Here are a few of them!
* [Geometrize][18] is a port of Primitive written in Haxe. There is also [a JS implementation][19] that you can try out directly [on your browser][20].
* [Primitive.js][21], which is a port of Primitive in JS. Also, [primitive.nextgen][22], which is a port of the Primitive desktop app using Primitive.js and Electron.
* There are a couple of Twitter accounts where you can see examples of images generated with Primitive and Geometrize. Check out [@PrimitivePic][23] and [@Geometrizer][24].
* [imagetracerjs][25], which is a raster image tracer and vectorizer written in JavaScript. There are also ports for [Java][26] and [Android][27].
--------------------------------------------------------------------------------
via: https://medium.freecodecamp.org/using-svg-as-placeholders-more-image-loading-techniques-bed1b810ab2c
作者:[ José M. Pérez][a]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://medium.freecodecamp.org/@jmperezperez?source=post_header_lockup
[1]:https://medium.com/@jmperezperez/how-medium-does-progressive-image-loading-fd1e4dc1ee3d
[2]:https://medium.com/@jmperezperez/using-webp-to-create-tiny-preview-images-3e9b924f28d6
[3]:https://medium.com/@jmperezperez/more-examples-of-progressive-image-loading-f258be9f440b
[4]:https://github.com/fraser-hemp/gradify
[5]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-281184-square.jpg
[6]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-281184-square-10.svg
[7]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-281184-square-100.svg
[8]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-618463-square.jpg
[9]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-618463-square-10.svg
[10]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-618463-square-100.svg
[11]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-281184-square-sqip.svg
[12]:https://jmperezperez.com/svg-placeholders/%28/assets/images/posts/svg-placeholders/pexels-photo-618463-square-sqip.svg
[13]:https://www.gatsbyjs.org/
[14]:https://www.npmjs.com/package/potrace
[15]:https://craftcms.com/
[16]:https://github.com/nystudio107/craft3-imageoptimize/blob/master/src/lib/Potracio.php
[17]:https://github.com/EmilTholin/image-trace-loader
[18]:https://github.com/Tw1ddle/geometrize-haxe
[19]:https://github.com/Tw1ddle/geometrize-haxe-web
[20]:http://www.samcodes.co.uk/project/geometrize-haxe-web/
[21]:https://github.com/ondras/primitive.js
[22]:https://github.com/cielito-lindo-productions/primitive.nextgen
[23]:https://twitter.com/PrimitivePic
[24]:https://twitter.com/Geometrizer
[25]:https://github.com/jankovicsandras/imagetracerjs
[26]:https://github.com/jankovicsandras/imagetracerjava
[27]:https://github.com/jankovicsandras/imagetracerandroid
[28]:https://medium.com/@jmperezperez/lazy-loading-images-on-the-web-to-improve-loading-time-and-saving-bandwidth-ec988b710290
[29]:https://www.youtube.com/watch?v=szmVNOnkwoU
[30]:https://medium.com/@jmperezperez/drawing-images-using-edge-detection-and-svg-animation-16a1a3676d3
[31]:https://medium.com/@jmperezperez/drawing-images-using-edge-detection-and-svg-animation-16a1a3676d3
[32]:https://medium.com/@jmperezperez/drawing-images-using-edge-detection-and-svg-animation-16a1a3676d3
[33]:https://jmperezperez.com/cssconfau16/#/45
[34]:https://jmperezperez.com/renderconf17/#/46
[35]:https://en.wikipedia.org/wiki/Delaunay_triangulation
[36]:https://github.com/possan/polyserver
[37]:https://github.com/technopagan/sqip
[38]:https://github.com/fogleman/primitive
[39]:https://github.com/technopagan/cjpeg-dssim
[40]:https://en.wikipedia.org/wiki/Structural_similarity
[41]:https://github.com/technopagan/sqip
[42]:https://github.com/fogleman/primitive
[43]:https://github.com/svg/svgo
[44]:https://medium.com/@jmperezperez/how-medium-does-progressive-image-loading-fd1e4dc1ee3d
[45]:https://medium.com/@jmperezperez/more-examples-of-progressive-image-loading-f258be9f440b
[46]:http://www.w3.org/2000/svg
[47]:https://twitter.com/mikaelainalem
[48]:https://codepen.io/ainalem/full/aLKxjm/
[49]:https://github.com/EmilTholin/image-trace-loader#options
[50]:https://www.npmjs.com/package/potrace#parameters
[51]:https://medium.com/@jmperezperez/using-webp-to-create-tiny-preview-images-3e9b924f28d6
[52]:https://news.ycombinator.com/item?id=15696596

View File

@ -0,0 +1,238 @@
怎么去使用 SVG 作为一个占位符,以及其它图像加载技术
============================================================
![](https://cdn-images-1.medium.com/max/1563/0*zJGl1vKLttcJGIL4.jpg)
从被用作占位符的图像中生成 SVGs。继续阅读
我对怎么去让 web 性能更优化和图像加载的更快充满了热情。对这些感兴趣的领域中的其中一项研究就是占位符:当图像还没有被加载的时候应该去展示些什么?
在前此天,我偶然发现了使用 SVG 的一些加载技术,随后,我将在这篇文章中去描述它。
在这篇文章中我们将涉及如下的主题:
* 不同的占位符类型的概述
* 基于 SVG 的占位符(边缘、形状、和轮廓)
* 自动化处理
### 不同的占位符类型的概述
以前 [我写的关于占位符和图像延迟加载lazy-loading][28] 的文章和 [关于它的讨论][29] 中。当进行一个图像的延迟加载时,一个很好的主意是去考虑提供一个东西作为占位符,因为,它可能会很大程序上影响用户的感知体验。以前我提供了几个选项:
![](https://cdn-images-1.medium.com/max/1563/0*jlMM144vAhH-0bEn.png)
在图像被加载之前,有几种办法去填充图像区域。
* 在图像区保持空白:在一个响应式设计的环境中,这种方式防止了内容的跳跃。这种布局从用户体验的角度来看是非常差的作法。但是,它是为了性能的考虑,否则,每次为了获取图像尺寸,浏览器被迫进行布局重计算,以为它留下空间。
* 占位符:在那里显示一个用户配置的图像。我们可以在背景上显示一个轮廓。它一直显示直到实际的图像被加载,它也被用于当请求失败或者当用户根本没有设置图像的情况下。这些图像一般都是矢量图,并且都选择尺寸非常小的内联图片。
* 固定的颜色:从图像中获取颜色,并将其作为占位符的背景颜色。这可能是主导的颜色,最具活力的 … 这个主意是基于你正在加载的图像,并且它将有助于在没有图像和图像加载完成之间进行平滑过渡。
* 模糊的图像也被称为模糊技术。你提供一个极小版本的图像然后再去过渡到完整的图像。最初的图像的像素和尺寸是极小的。为去除伪影图像artifacts the image被放大和模糊化。我在前面写的 [怎么去做中间的渐进加载的图像][1]、[使用 WebP 去创建极小的预览图像][2]、和 [渐进加载图像的更多示例][3] 中讨论过这方面的内容。
结果是,还有其它的更多的变化,并且许多聪明的人开发了其它的创建占位符的技术。
其中一个就是用梯度图代替固定的颜色。梯度图可以创建一个更精确的最终图像的预览,它整体上非常小(提升了有效载荷)。
![](https://cdn-images-1.medium.com/max/1250/0*ecPkBAl69ayvRctn.jpg)
使用梯度图作为背景。来自 Gradify 的截屏,它现在并不在线,代码 [在 GitHub][4]。
其它的技术是使用基于 SVGs 的技术,它在最近的实验和黑客中得到了一些支持。
### 基于 SVG 的占位符
我们知道 SVGs 是完美的矢量图像。在大多数情况下我们是希望去加载一个位图,所以,问题是怎么去矢量化一个图像。一些选择是使用边缘、形状和轮廓。
#### 边缘
在 [前面的文章中][30],我解释了怎么去找出一个图像的边缘和创建一个动画。我最初的目标是去尝试绘制区域,矢量化这个图像,但是,我并不知道该怎么去做到。我意识到使用边缘也可能被创新,并且,我决定去让它们动起来,创建一个 “绘制” 的效果。
[在以前,使用边缘检测绘制图像和 SVG 动画,在 SVG 中基本上不被使用和支持的。一段时间以后,我们开始用它去作为一个有趣的替代 … medium.com][31][][32]
#### 形状
SVG 也可以用于去从图像中绘制区域而不是边缘/边界。用这种方法,我们可以矢量化一个位图去创建一个占位符。
在以前,我尝试去用三角形做类似的事情。你可以在我的 [at CSSConf][33] 和 [Render Conf][34] 的演讲中看到它。
上面的 codepen 是一个由 245 个三角形组成的基于 SVG 占位符的观点的证明。生成的三角形是使用 [Possans polyserver][36] 基于 [Delaunay triangulation][35]。正如预期的那样,使用更多的三角形,文件尺寸就更大。
#### Primitive 和 SQIP一个基于 SVG 的 LQIP 技术
Tobias Baldauf 正在致力于另一个使用 SVGs 的被称为 [SQIP][37] 的低质量图像占位符技术。在深入研究 SQIP 之前,我先简单了解一下 [Primitive][38],它是基于 SQIP 的一个库。
Primitive 是非常吸引人的,我强烈建议你去了解一下。它讲解了一个位图怎么变成由重叠形状组成的 SVG。它尺寸比较小一个更小的往返更适合直接放置到页面中在一个初始的 HTML 载荷中,它是非常有意义的。
Primitive 基于像三角形、长方形、和圆形等形状去生成一个图像。在每一步中它增加一个新形状。很多步之后,图像的结果看起来非常接近原始图像。如果你输出的是 SVG它意味着输出代码的尺寸将很大。
为了理解 Primitive 是怎么工作的,我通过几个图像来跑一下它。我用 10 个形状和 100 个形状来为这个插画生成 SVGs
** 此处有Canvas,请手动处理 **
![](https://cdn-images-1.medium.com/max/625/1*y4sr9twkh_WyZh6h0yH98Q.png)
![](https://cdn-images-1.medium.com/max/625/1*cqyhYnx83LYvhGdmg2dFDw.png)
![](https://cdn-images-1.medium.com/max/625/1*qQP5160gPKQdysh0gFnNfw.jpeg)
Processing [this picture][5] 使用 Primitive使用 [10 个形状][6] 和 [100 形状][7]。
![](https://cdn-images-1.medium.com/max/625/1*PWZLlC4lrLO4CVv1GwR7qA.png)
![](https://cdn-images-1.medium.com/max/625/1*khnga22ldJKOZ2z45Srh8A.png)
![](https://cdn-images-1.medium.com/max/625/1*N-20rR7YGFXiDSqIeIyOjA.jpeg)
Processing [this picture][8] 使用 Primitive使用 [10 形状][9] 和 [100 形状][10]。
当在图像中使用 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 92L40262"/><path fill=”#f2e2ba” d=”M638 894L614 6l472 440"/><path fill=”#fff8be” d=”M-62 854h300L13862"/><path fill=”#76c2d9" d=”M41062L154 53062 38"/><path fill=”#62b4cf” d=”M10862L49830l484 508"/><path fill=”#010412" d=”M4302l196 5276 356"/><path fill=”#eb7d3f” d=”M598 594l48832308 520"/><path fill=”#080a18" d=”M198 418l32 304 116448"/><path fill=”#3f201d” d=”M1086 1062l-34452 248148"/><path fill=”#ebd29f” d=”M630 658l-60372 516 320"/></g></svg>
```
使用 100 个形状生成的图像是很大的,正如我们预期的那样,在 SVGO之前是 8kB之后加权大小为 ~5kB。它们在细节上已经很好了但是仍然是个很小的载荷。使用多少三角形主要取决于图像类型和细腻程序对比度、颜色数量、复杂度
它还可能去创建一个类似于 [cpeg-dssim][39] 的脚本,去调整所使用的形状的数量,以满足 [结构相似][40] 的阈值(或者最差情况中的最大数量)。
这些 SVG 的结果也可以用作背景图像。因为尺寸约束和矢量化,它们在图像和大规模的背景图像中是很好的选择。
#### SQIP
用 [Tobias 自己的话说][41]
> SQIP 是尝试在这两个极端之间找到一种平衡:它使用 [Primitive][42] 去生成一个由几种简单图像构成的近似图像的可见特征的 SVG使用 [SVGO][43] 去优化 SVG并且为它增加高斯模糊滤镜。产生的最终的 SVG 占位符加权后大小为 ~8001000 字节,在屏幕上看起来更为平滑,并提供一个可视的图像内容提示。
这个结果和使用一个极小的使用了模糊技术的占位符图像类似。what [Medium][44] and [other sites][45] do)。区别在于它们使用了一个位图图像,如 JPG 或者 WebP而这里是使用的占位符是 SVG。
如果我们使用 SQIP 而不是原始图像,我们将得到这样的效果:
![](https://cdn-images-1.medium.com/max/938/0*yUY1ZFP27vFYgj_o.png)
![](https://cdn-images-1.medium.com/max/938/0*DKoZP7DXFvUZJ34E.png)
[第一张图片][11] 和 [第二张][12] 的输出图像使用了 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-12316 43 128z"/><ellipse fill="#47332f" cx="214" cy="237" rx="242" ry="19"/></g></svg>
```
SQIP 也可以输出一个 Base 64 编码的 SVG 内容的图像标签:
```
<img width="640" height="640" src="example.jpg” alt="Add descriptive alt text" style="background-size: cover; background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAw…<stripped base 64>…PjwvZz48L3N2Zz4=);">
```
#### 轮廓
我们刚才看了使用了边缘和 primitive 形状的 SVG。另外一种可能是去矢量化图像以 “tracing” 它们。[Mikael 动画][47] 分享的 [a codepen][48],在几天前展示了怎么去使用两色轮廓作为一个占位符。结果非常漂亮:
![](https://cdn-images-1.medium.com/max/1250/1*r6HbVnBkISCQp_UVKjOJKQ.gif)
SVGs 在这种情况下是手工绘制的,但是,这种技术可以用工具快速生成并自动化处理。
* [Gatsby][13],一个 React 支持的描绘 SVGs 的静态网站生成器。它使用 [一个 potrace 算法的 JS 端口][14] 去矢量化图像。
* [Craft 3 CMS][15],它也增加了对轮廓的支持。它使用 [一个 potrace 算法的 PHP 端口][16]。
* [image-trace-loader][17],一个使用了 Potrace 算法去处理图像的 Webpack 加载器。
如果感兴趣,可以去看一下 Emil 的 webpack 加载器 (基于 potrace) 和 Mikael 的手工绘制 SVGs 之间的比较。
假设我使用一个默认选项的 potrace 生成输出。但是,有可能对它们进行调整。查看 [the options for image-trace-loader][49],它非常漂亮 [the ones passed down to potrace][50]。
### 总结
我们看到有不同的工具和技术去从图像中生成 SVGs并且使用它们作为占位符。与 [WebP 是一个奇妙格式的缩略图][51] 方式相同SVG 也是一个用于占位符的有趣的格式。我们可以控制细节的级别(和它们的大小),它是高可压缩的,并且很容易用 CSS 和 JS 进行处理。
#### 额外的资源
这篇文章发表于 [the top of Hacker News][52]。我非常感谢它,并且,在页面上的注释中的其它资源的全部有链接。下面是其中一部分。
* [Geometrize][18] 是用 Haxe 写的 Primitive 的一个端口。这个也是,[一个 JS 实现][19],你可以直接 [在你的浏览器上][20]尝试。
* [Primitive.js][21],它也是在 JS 中的一个 Primitive 端口,[primitive.nextgen][22],它是使用 Primitive.js 和 Electron 的 Primitive 的桌面版应用的一个端口。
* 这里有两个 Twitter 帐户,里面你可以看到一些用 Primitive 和 Geometrize 生成的图像示例。访问 [@PrimitivePic][23] 和 [@Geometrizer][24]。
* [imagetracerjs][25],它是在 JavaScript 中的光栅图像跟踪和矢量化程序。这里也有为 [Java][26] 和 [Android][27] 提供的端口。
--------------------------------------------------------------------------------
via: https://medium.freecodecamp.org/using-svg-as-placeholders-more-image-loading-techniques-bed1b810ab2c
作者:[ José M. Pérez][a]
译者:[qhwdw](https://github.com/qhwdw)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]:https://medium.freecodecamp.org/@jmperezperez?source=post_header_lockup
[1]:https://medium.com/@jmperezperez/how-medium-does-progressive-image-loading-fd1e4dc1ee3d
[2]:https://medium.com/@jmperezperez/using-webp-to-create-tiny-preview-images-3e9b924f28d6
[3]:https://medium.com/@jmperezperez/more-examples-of-progressive-image-loading-f258be9f440b
[4]:https://github.com/fraser-hemp/gradify
[5]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-281184-square.jpg
[6]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-281184-square-10.svg
[7]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-281184-square-100.svg
[8]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-618463-square.jpg
[9]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-618463-square-10.svg
[10]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-618463-square-100.svg
[11]:https://jmperezperez.com/assets/images/posts/svg-placeholders/pexels-photo-281184-square-sqip.svg
[12]:https://jmperezperez.com/svg-placeholders/%28/assets/images/posts/svg-placeholders/pexels-photo-618463-square-sqip.svg
[13]:https://www.gatsbyjs.org/
[14]:https://www.npmjs.com/package/potrace
[15]:https://craftcms.com/
[16]:https://github.com/nystudio107/craft3-imageoptimize/blob/master/src/lib/Potracio.php
[17]:https://github.com/EmilTholin/image-trace-loader
[18]:https://github.com/Tw1ddle/geometrize-haxe
[19]:https://github.com/Tw1ddle/geometrize-haxe-web
[20]:http://www.samcodes.co.uk/project/geometrize-haxe-web/
[21]:https://github.com/ondras/primitive.js
[22]:https://github.com/cielito-lindo-productions/primitive.nextgen
[23]:https://twitter.com/PrimitivePic
[24]:https://twitter.com/Geometrizer
[25]:https://github.com/jankovicsandras/imagetracerjs
[26]:https://github.com/jankovicsandras/imagetracerjava
[27]:https://github.com/jankovicsandras/imagetracerandroid
[28]:https://medium.com/@jmperezperez/lazy-loading-images-on-the-web-to-improve-loading-time-and-saving-bandwidth-ec988b710290
[29]:https://www.youtube.com/watch?v=szmVNOnkwoU
[30]:https://medium.com/@jmperezperez/drawing-images-using-edge-detection-and-svg-animation-16a1a3676d3
[31]:https://medium.com/@jmperezperez/drawing-images-using-edge-detection-and-svg-animation-16a1a3676d3
[32]:https://medium.com/@jmperezperez/drawing-images-using-edge-detection-and-svg-animation-16a1a3676d3
[33]:https://jmperezperez.com/cssconfau16/#/45
[34]:https://jmperezperez.com/renderconf17/#/46
[35]:https://en.wikipedia.org/wiki/Delaunay_triangulation
[36]:https://github.com/possan/polyserver
[37]:https://github.com/technopagan/sqip
[38]:https://github.com/fogleman/primitive
[39]:https://github.com/technopagan/cjpeg-dssim
[40]:https://en.wikipedia.org/wiki/Structural_similarity
[41]:https://github.com/technopagan/sqip
[42]:https://github.com/fogleman/primitive
[43]:https://github.com/svg/svgo
[44]:https://medium.com/@jmperezperez/how-medium-does-progressive-image-loading-fd1e4dc1ee3d
[45]:https://medium.com/@jmperezperez/more-examples-of-progressive-image-loading-f258be9f440b
[46]:http://www.w3.org/2000/svg
[47]:https://twitter.com/mikaelainalem
[48]:https://codepen.io/ainalem/full/aLKxjm/
[49]:https://github.com/EmilTholin/image-trace-loader#options
[50]:https://www.npmjs.com/package/potrace#parameters
[51]:https://medium.com/@jmperezperez/using-webp-to-create-tiny-preview-images-3e9b924f28d6
[52]:https://news.ycombinator.com/item?id=15696596