以下内容是 Emil Björklund 的客座文章。CSS 中的滤镜效果已经存在一段时间了,与混合模式等功能一起,它们为我们在浏览器中重新创建和操纵之前需要在 Photoshop 中完成的图像提供了新的可能性。在这里,Emil 探讨了一种使用更被遗忘的滤镜效果之一(即 *filter 函数*)的性能技巧,以及使用 SVG 重现该技巧。
这一切都始于 Facebook 工程团队关于如何在他们的原生应用程序中加载封面照片预览的文章。他们面临的问题是,这些“封面照片”很大,通常需要一段时间才能加载,当背景突然从纯色变为图像时,用户会体验到不理想的效果。
这种情况在连接性较差的网络或移动网络中尤其明显,在这种情况下,您往往会盯着一个空空的灰色框,等待图像下载。
理想情况下,图像应该在获取个人资料数据时被编码到应用程序的初始 API 响应中。但是,为了适应此请求,图像大小必须限制在 *200 字节* 内。这是一个难题,因为封面照片的大小超过了 100 *千字节*。
那么如何从 200 字节中获得有价值的东西,以及如何在图像完全加载之前向用户展示 *一些东西* 呢?
解决方案(巧妙无比)是返回一个非常小的图像(大约 40 像素宽),然后在应用高斯模糊的同时将该小图像放大。这会立即显示一个美观的背景,并提供封面图像外观的预览。然后,实际的封面图像可以在后台及时加载,并平滑地切换进来。真是明智之举!
这项技术有一些很酷的地方
- 它使得感知到的加载时间快如闪电。
- 它使用了一种在性能方面通常很昂贵的技术来 *提升性能*。
- 它可以在网络上实现。
大型标题背景图像(以及它们的性能缺陷)绝对是我们构建网络应用时可以理解的东西,因此这对我们很有用。我们可能会试图避免下载大型图像,但有时我们也会做出妥协,以达到某种效果。在这种情况下,我们能做的最好的事情就是尝试优化感知到的性能,因此我们不妨借鉴这项技术。
一个有效的示例
我们将使用类似“关键 CSS”的方法来重新创建此标题图像功能。第一个请求将加载一个很小的图像作为内联 CSS,然后高分辨率背景将在首次渲染后加载。
加载完成后,它会看起来像这样

在此示例中,我们使用了一个背景图像,将其视为装饰,而不是内容的一部分。关于何时将这类图像视为内容(因此编码为 <img>
)以及何时将其视为背景图像,有一些更精细的观点需要辩论。为了使用智能大小模式(例如 CSS 值 cover
和 contain
),背景图像可能是此类设计的常见解决方案,但像 object-fit
这样的新属性使得对内容图像采用相同方法变得更容易。像 Medium 这样的网站已经使用模糊的内容图像来改善加载时间,但这种技巧的有效性存在争议——如果加载技术失败,模糊的图像是否还有用?总之:在本文中,我们将重点介绍适用于背景图像的这种技术。
以下是工作原理的概要
- 将一个很小的图像预览(40×22 像素)作为 base64 编码的背景图像内联到
<style>
标签中。style 标签还包含通用样式和对背景图像应用高斯模糊的规则。最后,它还包含针对较大版本标题图像的样式,并作用域到不同的类名。 - 从内联 CSS 获取大型图像的 URL,并使用 JavaScript 预加载它。如果脚本由于某种原因失败,也不会有问题——模糊的背景图像仍然存在,看起来很酷。
- 当大型图像加载完成后,添加一个类名,该类名会切换 CSS 以使用大型图像作为背景,同时移除模糊效果。希望可以将移除模糊的效果动画化。
您可以在 Pen 中找到最终示例。您可能会看到在更清晰的图像加载之前短暂显示模糊的图像。如果没有,请尝试清空缓存后重新加载页面。
一个很小且经过优化的图像
首先,我们需要一个图像的预览版本。Facebook 通过压缩魔法(例如将不变的 JPEG 头部位存储在应用程序中)将他们的图像大小缩减到 200 字节,但我们无法达到这种程度。对于大小为 40×22 像素的图像,在经过一些图像优化软件处理后,该图像的大小约为 1000 字节。

完整大小的 JPEG 图像大小约为 120Kb,分辨率为 1500×823 像素。该文件大小可能可以更小,但我们将保持原样,因为它只是一个概念验证。在实际应用中,您可能会有几个图像尺寸变体,并根据视窗大小加载不同的尺寸——甚至可能加载不同的格式,比如 WebP。
filter
函数
用于图像的 接下来,我们要将小图像放大以覆盖元素,但我们不希望它看起来像素化且难看。这就是 filter()
函数发挥作用的地方。CSS 中的滤镜可能看起来有点让人困惑,因为实际上存在三种类型的滤镜:filter
属性、它提出的 backdrop-filter
对等体(在 Filter Effects Level 2 规范 中),以及用于图像的 filter()
函数。让我们先看看 *属性*。
.myThing {
filter: hue-rotate(45deg);
}
将应用一个或多个滤镜,每个滤镜都作用于之前滤镜的结果——非常像一个转换列表。我们有一系列预定义的滤镜 可供使用:blur()
、brightness()
、contrast()
、drop-shadow()
、grayscale()
、hue-rotate()
、invert()
、opacity()
、sepia()
和 saturate()
。
更酷的是,这是一个 CSS 和 SVG 共享的规范,因此不仅在 SVG 中对预定义滤镜进行了规范,我们还可以创建自己的 SVG 滤镜并从 CSS 中引用它们。
.myThing {
filter: url(myfilter.svg#myCustomFilter);
}
相同的滤镜效果在 backdrop-filter
中也是有效的,在将透明元素与其背景合成时应用这些效果——这对于创建 “磨砂玻璃”效果 可能最有帮助。
最后,还有用于图像值的 filter()
函数。想法是在任何可以引用 CSS 中图像的地方,您也应该能够将其通过一系列滤镜。对于小型标题图像,我们将其作为 base64 数据 URI 内联,并将其通过 blur()
滤镜。
.post-header {
background-image: filter(url(data:image/jpeg;base64,/9j/4AAQ ...[truncated] ...), blur(20px));
}
这很棒,因为这正是我们在重新创建 Facebook 应用程序中的技术时所需要的!但在支持方面有一个坏消息。filter
*属性* 在除了 IE 之外的所有最新浏览器版本中都受支持,但 除了 WebKit 之外,没有其他浏览器 实现规范的 filter()
*函数* 部分。
在这里我所说的 WebKit 是指撰写本文时 WebKit 的夜间构建版本,而不是 Safari。用于图像的 filter
函数 *确实* 在 iOS9 中以 -webkit-filter()
的形式存在,但我能找到的官方资料中都没有报道过这一点,这有点奇怪。原因可能是它与 background-size
存在一个非常糟糕的 错误:不会调整原始图像的大小,但会调整过滤输出的平铺大小。这会严重破坏背景图像功能,尤其是在模糊的情况下。该错误已修复,但没有及时修复以使其进入 Safari 9 版本,因此我猜他们不想宣布该功能。
但是对于缺少或损坏的 filter()
功能,我们该怎么办呢?我们可以让不支持该功能的浏览器使用纯色背景,直到图像加载完成,但这意味着如果 JS 无法加载,他们将根本无法看到背景。太无聊了!
不,我们将 filter()
函数保存为以后对替换后的图像进行动画处理的额外调味料,而是使用 SVG 模拟初始图像的滤镜函数。
使用 SVG 重新创建模糊滤镜
由于规范方便地提供了一个 用于 blur()
滤镜的 SVG 等效项,因此我们可以通过一些调整,使用 SVG 重新创建模糊滤镜的工作原理。
- 应用高斯模糊后,边缘会变得有点半透明。我们可以通过添加一个名为
feComponentTransfer
的滤镜来修复这个问题。组件转换允许您操纵源图形的每个颜色通道(包括 alpha)。这种特殊的变体使用feFuncA
元素,它将 alpha 通道中0
到1
之间的任何值映射到1
,这意味着它会移除任何 alpha 透明度。 <filter>
元素上的color-interpolation-filters
属性必须设置为sRGB
。SVG 滤镜默认使用linearRGB
色彩空间,而 CSS 使用sRGB
。大多数浏览器似乎能够正确处理颜色校正,但除非设置此值,否则 Safari/WebKit 会使所有颜色都变淡。filterUnits
设置为userSpaceOnUse
,简单来说,这意味着坐标和长度(比如模糊的stdDeviation
)会映射到我们应用模糊的元素的像素上。
生成的 SVG 代码看起来像这样
<filter id="blur" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="20" edgeMode="duplicate" />
<feComponentTransfer>
<feFuncA type="discrete" tableValues="1 1" />
</feComponentTransfer>
</filter>
filter
属性使用它自己的 url()
函数,我们可以使用它来引用或 URI 编码 SVG 过滤器。那么,我们如何将过滤器应用到 background-image: url(...)
中的内容呢?
好吧,SVG 文件可以指向其他图像,并且我们可以将过滤器应用到 SVG 中的这些图像。问题是,SVG 背景图像无法获取任何外部资源。但是,我们可以通过在 SVG 中对 JPG 进行 base64 编码来解决这个问题。对于大型图像来说,这不可行,但对于我们的小图像来说应该没问题。SVG 将看起来像这样
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="1500" height="823"
viewBox="0 0 1500 823">
<filter id="blur" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="20 20" edgeMode="duplicate" />
<feComponentTransfer>
<feFuncA type="discrete" tableValues="1 1" />
</feComponentTransfer>
</filter>
<image filter="url(#blur)"
xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJ ...[truncated]..."
x="0" y="0"
height="100%" width="100%"/>
</svg>
另一个缺点(与直接使用 filter()
函数和位图相比)是我们需要手动设置一些大小,才能使 SVG 与背景大小配合得当。SVG 本身有一个 viewBox
,设置为模拟图像的纵横比,并且 width
和 height
属性设置为相同的测量值,以确保它在跨浏览器中都能正常工作(例如,如果缺少这些属性,IE 会搞乱纵横比)。最后,<image>
元素设置为覆盖整个 SVG 画布。
现在,我们可以将此文件用作文章标题的背景,它将看起来像这样

最后一步,我们可以将 SVG 包装器图像内联到 CSS 中,以避免额外的请求。内联 SVG 需要进行 URI 编码,我使用 yoksel 的 SVG 编码器 来完成此操作。所以,现在我们有一个包含另一个 dataURI 的 dataURI。DataURInception!
在编码 SVG 时,我们会得到一些要粘贴到 url()
中的文本,但需要注意的是,我们需要在前面添加一些元数据才能使其显示:data:image/svg+xml;charset=utf-8,
。charset
部分很重要:它使编码的 SVG 在跨浏览器中都能正常工作。
.post-header {
background-color: #567DA7;
background-size: cover;
background-image: url(data:image/svg+xml;charset=utf-8,%3Csvg...);
}
此时,整个页面(包括图像)在使用 GZIP 时只有 1 个请求和 5KB。
获取大型图像的 URL
接下来,我们为增强型标题创建一个规则,在其中设置大型背景图像。
.post-header-enhanced {
background-image: url(largeimg.jpg);
}
我们不希望仅仅切换类名,从而触发大型图像加载,而是希望预加载大型图像,然后才应用类名。这样,我们就可以在以后平滑地动画切换,并合理地确保大型图像已完成加载。由于我们不想在 CSS 和 JavaScript 中都硬编码图像 URL,因此我们将使用 JavaScript 从样式中获取 URL。由于类名尚未应用,因此我们不能只查看 headerElement.style.backgroundImage
等 - 它不知道背景是什么。为了解决这个问题,我们将使用 CSSOM - CSS 对象模型,以及允许我们遍历 CSS 规则的只读 JS 属性。
以下代码片段会找到增强型标题的类名,然后使用一些正则表达式获取 URL。之后,它会预加载图像,并在图像加载完成后触发添加的类名。
<script>
window.onload = function loadStuff() {
var win, doc, img, header, enhancedClass;
// Quit early if older browser (e.g. IE 8).
if (!('addEventListener' in window)) {
return;
}
win = window;
doc = win.document;
img = new Image();
header = doc.querySelector('.post-header');
enhancedClass = 'post-header-enhanced';
// Rather convoluted, but parses out the first mention of a background
// image url for the enhanced header, even if the style is not applied.
var bigSrc = (function () {
// Find all of the CssRule objects inside the inline stylesheet
var styles = doc.querySelector('style').sheet.cssRules;
// Fetch the background-image declaration...
var bgDecl = (function () {
// ...via a self-executing function, where a loop is run
var bgStyle, i, l = styles.length;
for (i=0; i<l; i++) {
// ...checking if the rule is the one targeting the
// enhanced header.
if (styles[i].selectorText &&
styles[i].selectorText == '.'+enhancedClass) {
// If so, set bgDecl to the entire background-image
// value of that rule
bgStyle = styles[i].style.backgroundImage;
// ...and break the loop.
break;
}
}
// ...and return that text.
return bgStyle;
}());
// Finally, return a match for the URL inside the background-image
// by using a fancy regex I Googled up, as long as the bgDecl
// variable is assigned at all.
return bgDecl && bgDecl.match(/(?:\(['|"]?)(.*?)(?:['|"]?\))/)[1];
}());
// Assign an onLoad handler to the dummy image *before* assigning the src
img.onload = function () {
header.className += ' ' +enhancedClass;
};
// Finally, trigger the whole preloading chain by giving the dummy
// image its source.
if (bigSrc) {
img.src = bigSrc;
}
};
</script>
如果 addEventListener
不受支持,脚本会提前退出,这应该与所需的其余支持很好地重叠。据我所知,所有合理现代的 SVG 支持浏览器都支持 CSSOM 和其他使用的 JavaScript 功能。
动画切换
我们没有能够使用 filter()
函数,这有点可惜,因为我们已经发现了它的存在。所以,我们将添加一个动画效果,在切换到高分辨率图像时使用。目前,这只有在 WebKit nightly 版本中才有效,我们可以安全地使用 @supports
规则来限制更改范围。这是一个动画 GIF,展示了该效果的实际操作

注意,我们不能为此使用 transition
:filter()
函数是可以动画化的,但仅限于更改过滤器链中的值 - 当背景图像更改时,我们就会遇到问题。但是,我们可以为此使用动画,但这意味着我们需要将背景图像的 URL 重复两次,作为起始值和结束值。这只是一个小小的代价。
以下是支持 filter()
函数的浏览器的增强型标题样式的 CSS 代码
@supports (background-image: filter(url('i.jpg'), blur(1px))) {
.post-header {
transform: translateZ(0);
}
.post-header-enhanced {
animation: sharpen .5s both;
}
@keyframes sharpen {
from {
background-image: filter(largeimg.jpg), blur(20px));
}
to {
background-image: filter(largeimg.jpg), blur(0px));
}
}
}
最后一个细节是标题上的 translateZ(0)
技巧:没有它,动画会非常卡顿。我尝试使用所有现代方法,并使用了 will-change: background-image
,但这并没有说服浏览器创建硬件支持的层,因此我不得不使用旧的技巧,即 添加一个 3D "空变换"。
快速、渐进增强型背景图像
我们已经得到了一个带有巨大背景图像(虽然是模糊的)的页面,它在 5KB 内加载,并延迟加载清晰的完整尺寸图像。目前,只有 WebKit 可以为更清晰的图像进行动画处理,但我希望其他浏览器也能很快实现 filter()
函数。我相信我们可以使用它来实现更多有趣的技巧。
一个字形容:史诗级。谢谢!
非常酷。
你对用纯 CSS 实现有什么想法吗?
类似这样...
谢谢!
我不太确定你所说的 "用纯 CSS 实现" 是什么意思,以及你的代码应该如何不同 - 你可以稍微解释一下吗?我非常乐意使用 CSS 来做更多事情。:-)
嗨,Emil,
抱歉,我意识到那行不通,这已经是一天很长了,但我仍然认为这是有可能的。
如果我理解正确,你似乎正在使用 JS 来预加载大型图像,然后向元素添加一个类,以便将图像动画到合适的位置。
http://codepen.io/M_J_Robbins/pen/aOxPXe/
这里,我像你一样内联加载了小图像。
然后,在 1 秒后,我使用动画预加载大型图像。
然后,在 5 秒后淡入。(时间是夸张的,为了效果,我不确定最佳时间是什么)。
欢呼,
Mark
啊,我明白了。是的,这很酷,我想唯一的问题是,它将对大型图像何时加载完成进行 "估计"。我想我的想法是 "加载一些极快的图像,然后使用 JS 来决定下一步该做什么",这可以推广到其他解决方案 - 图像格式、根本不加载大型图像...
啊,是的,有道理,我无法想到用纯 CSS 来检测这一点的方法。
我是一名邮件开发者,所以总是喜欢不用 JS 的解决方案 :)
欢呼
Emil,好文章!这让我想到,使用这种技术来加载渐进式 JPEG,并在
loadend
事件上切换模糊效果会很酷。你对此有什么想法吗?也许请求 + 加载图像的第一部分的开销会超过添加缩略图的额外工作吗?谢谢,Simon!(还有,你好!好久不见了!)
这是一个非常酷的想法,但我猜想这只会对
<img>
有用,对吧?CSS 背景图像没有加载事件... 我有点怀疑对内容图像使用模糊,因为除非图像正确加载,否则模糊图像不会添加任何内容,而背景图像即使模糊仍然可以是装饰性的。这与渐进式 JPEG 相比如何?
像这样的文章提醒我,让
lowsrc
过时是一个错误。很棒的文章,很聪明!但对于我来说,这种效果引发了网络可访问性问题。
我担心模糊/聚焦模式(一般而言)可能会对视力或认知能力障碍的用户造成一些困扰。例如,如果用户本身就难以自然地集中注意力,那么如果背景也正在聚焦,这可能会更难... 几乎就像景深效果。
对于许多用户来说,网络本身就已经很模糊了,即使是渐进式的图像加载,其影响可能也比像这样从模糊到清晰的渐变过渡的影响要小。
由于这种效果需要 JavaScript 来向用户提供清晰的图像,而且你无法保证用户的浏览器何时会下载并执行该 JavaScript,因此这种效果可能会在任何时候发生... 或者根本不发生。这可能会让用户将注意力从内容上转移,来处理这种效果,然后再回到内容上。
如果用户的注意力一直在斗争,那么页面加载速度越快就越没有意义。
嗨,Joe,感谢你的反馈。你提了一个非常好的观点,也许适用于很多涉及动画的不同场景——它存在着分散注意力和造成混淆的风险。如果有充分的证据表明动画焦点效果不利于无障碍访问,我很乐意在“实时”产品中省略这部分。
尽管如此,动画对于该技术来说并非至关重要——它更多的是用一种有趣的方式来演示
filter()
函数的功能。在我看来,“小图片 + 模糊 = 超快首屏渲染”这部分更有趣,另外还有在 SVG 中“填充”filter()
函数。所以,除非我遗漏了什么——一旦你看到它变清晰一次,你将永远不会再看到它模糊?CodePen 示例就是这样运行的。
但我可能漏掉了什么 :(
那是理想的;)
图像被缓存,不需要模糊。
但正如 Emil 所说
这是因为你已经在浏览器的缓存中拥有了图像。
尝试在另一个浏览器或隐身窗口中打开它。
我认为这是一个有用的概念验证,但我想要补充一点
如果你正在开发一个大型、复杂的网站,你经常会发现资源会阻塞渲染,这包括所有的 CSS 和 head 中的所有同步 JS。问题在于,即使你内联的 base64 小图片在不利的情况下也无法在最初的几秒钟内开始绘制,因此,用户实际上仍然会在几秒钟内看到空白,然后是模糊图像,几乎立即接着是实际图像。
这不是你方法中的错误,我只是想强调,内联 CSS 不会使其立即渲染。该声明仍然必须等待页面上所有 CSS 加载并解析。你甚至可以内联一个纯色背景,它也不会在所有 CSS 加载并解析之前渲染。
因此,这种解决方案只对那些不阻塞渲染的网站有意义,而根据我的经验,很少有网站是如此优化的。
顺便说一句,第二个说明:如果你改为使用前景图像,它实际上可能比你当前的模糊图像加载得更快。原因是浏览器的预读解析器,它会立即开始加载该图像,而你的模糊图像仍然在等待页面上所有 CSS 以及所有阻塞 JS。
总结一下,实际情况可能不像许多人预期的那样
内联并不意味着即时渲染,它仍然可能需要几秒钟
传统的 前景图像可能会胜过任何基于 CSS 或 JS 的解决方案
结果可能会有所不同,因此请确保查看你情况下的时间线。
还有一个小的细节——如果你的大图像和小图像具有相同的比例,将会更精确,因为可以避免动画跳跃和图像在过渡期间移动。在我的项目中,我使用平均背景色来覆盖加载的第一阶段(在小图像之前),但在你的情况下(内联 css),这没有必要。
你如何计算照片的平均颜色?
谢谢!
尝试使用 Color Theif。这是一个小型 JS 库,用于获取图像的例如主色。
感谢你的解答!
对于小图片,你可以使用 PNG,它在小尺寸下比 JPEG 更省空间。
是的,我对各种格式进行了不少实验,但 JPEG 仍然是这个场景中“物超所值”的格式,即使是在较小尺寸下(以及图像优化之后)。
不一定是。在这种情况下,不是。
PNG 格式的小图像(40×22)重 1.78KB。JPG 格式的 473B,质量为 35%。
如果图像使用的颜色更少且更平滑,那当然有可能。
注意:确保你进行性能测试,尤其是在移动设备上。Android 设备的 CSS 性能相对较差,尤其是在 Android v5 之前的版本。模糊全宽背景图像会影响渲染速度,因此在应用之前,请务必了解权衡取舍。
也就是说,如果设备能够处理,效果就太棒了 :)
很棒的文章!我最近发布了关于 Medium 使用的技术来实现这一点。在他们的案例中,他们使用画布来应用 blur() 效果。
关于经过优化的微型图像,如果 WebP 是一个选项,我强烈建议你尝试一下。WebP 使用最高压缩设置生成的图像比使用 JPG 在最大压缩情况下生成的图像小 75%,至少在应用于这些微型图像时是这样。我对 https://jmperezperez.com/webp-placeholder-images/ 进行了一些研究。
如果你在正文中使用此技术,而不是只在标题中使用,那么这意味着如果你保存了一些内容以供离线阅读(例如,在 Safari 阅读列表中),图像实际上永远不会加载。在使用此技术之前,请三思而后行,尤其是在图像对于理解内容至关重要的情况下。
不错,我想知道它在低规格设备上的性能如何,我认为动画模糊过滤器会消耗不少资源。
使用两个 div 可能会更高效,一个 div 包含内联的小图片(在后面),另一个 div 包含大图片(在前面)。大图片的
opacity: 0
,当大图片加载完成后,它会过渡到opacity: 1
。效果可能相似(可能没有那么美观),但我认为在低端设备上,更简单的操作会运行得更好。它也能在 IE 和旧版 Android 浏览器上运行(与filter()
不同)。非常喜欢这个概念,可能会在我的工作室的投资组合网站以及一个或多个有大型背景图像的客户网站上使用它。
然而,我只想指出,至少在我的环境中(在一台 1.7 GHz rMBP 和 10 Mbps 连接上),我无法让演示在任何浏览器中正常工作,即使是在强制加载不使用缓存的情况下。在 Safari 上,它直接跳转到全分辨率图像;在 FF 和 Chrome 上,它最初显示模糊版本,然后直接跳转到全分辨率图像,没有过渡。120k 在当今时代对于大型背景图像来说似乎太小了。为了确保演示能够在具有良好宽带连接的人员那里正常工作,你可能要考虑将大小增加到至少 500k。
关于更好的浏览器支持:它可能没有那么流畅,但你不能在真正的标题上方创建一个第二个 div,让模糊背景位于其中吗?然后,一旦你延迟加载了真实图像并将其放在适当位置,就可以使用
opacity
来淡出模糊图像?理想情况下,应该能够将模糊过渡出去,而不是直接过渡到非模糊图像,但这种解决方案可以让过渡在更多类型的浏览器中工作。我讨厌 Medium 上的东西。这是 Medium 中唯一令人恼火的地方。
现在我将在许多网站上看到更多这种东西。.
切!
这是一篇很棒的文章,感谢分享,Emil。
你所拥有的那个大约 1KB 的 40×22 微型图像可以再减少 50%,大约为 473B。
你可以在此处查看/下载它:http://imgur.com/rke9rgE
你猜我用什么来压缩它?世界上最好的图像压缩引擎:Adobe Fireworks;)
对于任何使用 WordPress 并想要使用此技术的网站,我们已在此处实现了一个类似的解决方案,使其能够自动运行,作为 WordPress 插件:https://wordpress.org/plugins/featured-image-sharpen-up/
不确定 Facebook 能否将所有功劳归功于自己。Google 地图自创建以来就广泛使用了这项技术。(更多地用于卫星图像,甚至更多地用于街景)。
不幸的是,你的 SVG 解决方案似乎在所有版本的 IE + Edge 上都失败了,但我无法理解原因。
看,如果在 img(src=”data:…”)中使用 SVG,它可以直接使用,但如果用作背景图像,除非背景大小为 1280px 或更小,否则它将无法显示。为什么是 1280?不知道。
经过一番研究,问题似乎出在过滤器上。如果从 SVG 中删除过滤器,背景图像将渲染,但当然没有模糊效果,而模糊效果是整个目的。
天哪,我刚想到一个可怕的主意。我可以永远地编写一个解决方案,我在一个 div 之上绝对定位一个图像,以某种方式模拟一个背景图像。
实际上,在我仔细考虑了我的可怕主意之后…它并不那么糟糕。
可以将 svg 图像定位在 div 之上,并将 div 内的所有内容定位为相对,并具有比 svg 更高的 z-index 和不透明度。
然后,一旦大型图像加载完毕,你将该图像添加为 div 的背景图像,然后将 SVG 的不透明度降低到 0,并进行过渡,从而逆转模糊效果,这将在所有支持 SVG 过滤器和不透明度的浏览器中起作用(IE10+?)。
或者,我可以…不这样做,然后躲在角落里哭泣。
嗨 Eli,感谢你的反馈。我在 IE 或 Edge 上没有看到你描述的任何问题 - 在各种版本、屏幕尺寸和操作系统上进行了测试(来自 modern.ie 的干净虚拟机)。大多数情况下,它运行良好,但显然没有动画部分。
最接近的是,模糊图像有时在清晰图像加载之前不会显示,但我无法可靠地重现这种情况。
我的直觉是,在较大的视窗大小上,IE 上的 SVG 过滤器的性能很差,因此它在清晰图像加载之前没有时间渲染模糊。也许吧。这确实是一种概念验证技术(至少在我看来),因此在不同浏览器上的表现可能会有很大差异… :-)
这不是性能问题。如果 SVG 在任何时候都超过 1280px,它将不会作为背景渲染。
试试这个笔,它经过修改,因此 JS 实际上从未添加过大型图像。
http://codepen.io/anon/pen/BjRBXY
SVG 在 IE+Edge 上永远不会渲染,但在其他任何地方都可以正常运行。
有趣的是 - 我刚刚在没有 JS 的 IE10/Win7、IE10/Win8、IE11/Win7、Edge 12/Win10 和 Edge13/Win10 上再次进行了测试 - 所有 IE 在我的机器上都运行良好(即在任何屏幕尺寸上都显示模糊的 SVG),但我可以在两个 Edge 版本中复制 1280 像素错误。
听起来像是 Edge 团队的一个有趣的错误,我会向他们发送报告。 :-)
可能是 Windows 10 的问题。在进一步测试后,发现 Win7 上的 ie11 很好,但 Windows 10 上的 ie11 存在 1280 问题。
(请原谅双重发布。我意外地在下面创建了一个新的回复,但你可能不会收到它的通知)
可能是 Windows 10 的问题。在进一步测试后,发现 Win7 上的 ie11 很好,但 Windows 10 上的 ie11 存在 1280 问题。
读者 Ryvan Prabhu 写道
https://github.com/ryvan-js/bleach
Wout Mertens 写道