这始于看到 Mandy Michael 最近的一篇 Pen 关于 文本效果演示。我是一个视觉动物,所以我首先注意到的是效果,而不是标题(标题清楚地说明了效果是如何实现的)。瞬间,我的脑海里就浮现出“混合模式!”,结果证明这是错误的。
演示实际上使用的是 clip-path
。首先,文本被复制。我们有一个黑色文本在下层作为元素的实际文本内容,有一个白色文本在上层作为 content
属性的值(取自一个通过 JS 更新的数据属性)。这两个文本彼此叠加(完全重叠)。然后,带有白色文本的伪元素被剪裁成黑色连衣裙的形状。
但是,这意味着如果我们更改图像,我们需要更改剪裁路径,而且在这一点上,使用开发者工具找出具有许多点的多边形剪裁路径并非易事(这就是为什么像 Benett Feely 的 Clippy 这样的工具在开发者工具中直接进行双向编辑会非常有用)。因此我决定尝试一下我最初的想法——混合模式。
假设我们有一个 contentEditable
1 容器中的标题,带有黑白图像(即灰度)background
。HTML 结构如下
<header>
<h2 contentEditable role='textbox' aria-multiline='true'>And stay alive</h2>
</header>
我们在 header
容器上设置 background-image
,将 h2
文本设置为白色并设置其 mix-blend-mode
为 difference
或 exclusion
。相关的 CSS 如下
header { background: url(black-and-white-image.jpg) }
h2 {
color: white;
mix-blend-mode: difference;
}
我不能真正理解混合模式,也通常看不出 difference
和 exclusion
之间的区别,但是 根据 MDN 的说法,它们基本上是一样的,exclusion
的对比度更低。我能理解这种情况是,在图像上使用白色文本会得到一个结果,即图像在文本重叠的地方被反转。对于简单的黑白图像,原始图像中的黑色在白色文本覆盖的地方变为白色,原始图像中的白色在白色文本覆盖的地方变为黑色。
结果可以在下面的 Pen 中看到
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
任务完成!文本和图像都可以更改,效果保持不变,无需任何 JavaScript 或任何 CSS 更改。
但我立即发现另一个需要解决的问题:如果图像不仅仅是黑白怎么办?好吧,让我们试试!结果证明,结果实际上看起来还不错
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
但是,文本不再是灰度的,设置 filter: grayscale(1)
不会改变任何东西。是否有任何 filter
值有效?好吧,接下来尝试了 drop-shadow()
来找到这个问题的答案。答案是,是的,drop-shadow()
有效,但它的工作方式——阴影与 header
背景2 混合——提供了一个线索,说明为什么 grayscale()
不会改变任何东西:过滤器是在混合之前应用的,我们的文本是白色的,grayscale()
在这种情况下输出与其输入相同(白色输入,白色输出)。而且,由于在混合之前没有任何变化,因此其结果也是一样的。
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
这可能不应该让人感到意外。我之前遇到过因属性应用顺序导致的问题。
例如,filter
也是在 clip-path
之前应用的,所以如果我们把一个元素剪裁成非矩形形状,并且我们想在这个元素上添加一个投影,那么很不幸,在同一个元素上设置 filter
不会得到预期的结果。这是因为矩形元素被应用了 filter
,因此我们会在其矩形框周围有一个投影,并且 仅此之后 才会剪裁成通过 clip-path
指定的形状。无论你在 CSS 中设置它们的顺序如何,这两个属性的应用顺序始终如此。

filter
和 clip-path
时应用方式的示意图。解决 filter
+ clip-path
问题的办法是,在父元素上设置 filter
,并且父元素除了被剪裁的子元素之外没有任何可见内容。这里的“没有任何可见内容”很重要,因为如果父元素有一些可见的文本或边框,它们也会得到投影,而如果父元素有背景,那么整个背景区域都会得到投影。
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
但是,这个解决方案不适用于 filter
+ mix-blend-mode
问题。将我们的 h2
包裹在一个 div
中,并在该 div
上设置 filter
会破坏混合效果。
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
更糟糕的是,我似乎无法想到任何可以解决这个问题的方法。可能可以通过复制文本并使用 luminosity
混合模式来实现,但是,正如前面提到的,我不太理解混合模式,而且我还没有能做到这一点。
但也许我们可以尝试完全不同的方法,一种不使用混合的方法。所有关于过滤器的尝试让我想到,我们可以将图像应用于文本,然后应用 invert()
过滤器,然后可以将 grayscale()
、contrast()
等与之串联。
使用 background-clip: text
的这种方法,我们还有一个跨浏览器解决方案的优势,因为 Firefox 和 Edge 现在也实现了它。
我们的方法如下:确保 header
和 h2
有相同的背景,并且这些背景完全重叠。然后,在 h2
上设置 color: transparent
,并将它的背景剪裁为 text
。最后一步是在 h2
上设置 filter: invert(1)
。相关的 CSS3 如下
h2 {
background: inherit;
background-clip: text;
color: transparent;
filter: invert(1);
}
结果可以在下面的 Pen 中看到
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
它看起来和以前一样,只是使用了不同的方法,现在我们可以将更多函数与 filter
属性串联。例如,我们可以将文本设置为灰度并提高其对比度
filter: invert(1) grayscale(1) contrast(9)
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
调整 filter
值也是我们添加文本阴影的方式。虽然在第一种情况下(使用 mix-blend-mode
)我们可以简单地设置 text-shadow
属性(并且阴影也会与背景混合),但在第二种情况下这样做会导致问题
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
幸运的是,我们可以将 drop-shadow()
与我们的过滤器串联。
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
下面的 Pen 展示了本文中描述的两种方法。左边是 mix-blend-mode
方法,右边是 background-clip
和 filter
方法(包含额外的灰度和对比度组件)。文本是可编辑的,缩略图允许更改 background-image
查看 thebabydino 的 Pen (@thebabydino) 在 CodePen 上。
所以,如果我们比较这两种方法,哪种更好呢?
我们不会谈论美观问题,因为这是一个主观问题,而且它可能因情况而异,甚至因心情而异。
就基本支持而言,最后一种方法更占优势,因为它在 Edge 中得到支持,而 mix-blend-mode
则没有(但如果你希望它在 Edge 中可用,请 为它投票,因为 您的反馈很重要)。Mandy 最初的示例使用的是 clip-path
,这是另一个非常有用的功能,但不幸的是,它在 Edge 中也不起作用(你可以 在这里为它投票)。
当涉及到选择文本时,mix-blend-mode
方法可以完美地工作,并且在它支持的浏览器中看起来最好。

mix-blend-mode
方法选择文本使用 clip-path
方法,选择看起来很干净,文本仍然可读,但在我使用伪元素文本时,它似乎在 Firefox 中出现问题。幸运的是,这个问题有一个简单的解决方法:在伪元素上设置 pointer-events: none
。

clip-path
方法在 Firefox 中选择文本至于最后一种方法,选择看起来可能很丑,并且可能使文本更难阅读。更不用说,在这种情况下,投影最终被应用于整个选择矩形,而不仅仅是实际文本。

background-clip: text
+ filter
方法选择文本使用最后一种方法在 Firefox 中更改文本也会变得很麻烦,因为当我键入新文本时,屏幕会变得“脏”。

background-clip: text
+ filter
方法在 Firefox 中更改文本clip-path
方法最初在 Firefox 中更改文本时也存在问题:尝试从伪元素文本的中间开始编辑不起作用。幸运的是,在伪元素上设置 pointer-events: none
也可以解决这个问题。

clip-path
方法在 Firefox 中更改文本就文本的改变灵活性而言,最后一种方法表现最好,因为将过滤器函数串联起来可以让我们走很远。
最终,哪种方法更好取决于具体的用例。应该支持哪些浏览器?图像是否会更改?文本是否会更改?文本应该如何进行视觉调整?
1 contentEditable
默认情况下并非所有浏览器都支持,因此我们需要提供语义来解决这个问题。
2 在尝试混合模式时,请注意它们可能产生的可读性问题,特别是关于对比度的。 WCAG 2.0 规定,除非文本构成纯粹的装饰性图像的一部分,否则它应该通过最低对比度阈值。 像 Color ContrastAnalyzer 这样的工具可以帮助您满足该要求。
3 为了简洁起见,省略了前缀,但 background-clip
仍然需要 -webkit-
前缀才能在 WebKit 浏览器(Firefox 和 Edge 已实现它没有前缀,尽管 它们都支持 -webkit-
前缀,可能是因为 -webkit-
前缀已经被用烂了,并且 只 使用了该前缀),并且需要手动添加此前缀或通过预处理器混合,这是我通常不鼓励的,但在这种特殊情况下,通过 Autoprefixer 或 Prefixfree 的自动前缀添加不会发生(Prefixfree 通过功能检测工作,它不会捕获 background-clip
、filter
或 clip-path
等属性,这是 Autoprefixer 问题)。至于 filter
,它现在 支持 在所有当前的桌面浏览器中没有前缀,Autoprefixer 可以为它添加前缀。
很棒的工作。感谢分享!
我在 CSS Tricks 上见过的最令人惊叹的东西,也许是永远。我迫不及待地想下次遇到这个问题时再用它!
很喜欢。这是对我以前做法的很大改进。我寻找了一种方法,使它可以针对来自未知来源的平面颜色起作用。
谢谢!我将回去更新一些代码:)
这是一个救命技巧,我通常使用 svg 遮罩来获得这种效果。浏览器兼容性怎么样?
对任何 Microsoft 浏览器(IE、Edge)都不起作用。
“对任何 Microsoft 浏览器(IE、Edge)都不起作用。”
这不是关于网络相关事物的标准免责声明吗?我每天都会阅读帖子/文章/等等,不可避免地,快到结尾的时候,他们会带有这个免责声明。现在我认为 Microsoft 浏览器应该只用作 Chrome 安装应用程序。
IE 已经死了,并且被埋葬了。葬礼在两年前就结束了。很抱歉您没有吃到任何葬礼蛋糕。无论如何,几年后挖出死人有一种令人讨厌的习惯,会带来一些顽固的臭味,所以我不会推荐它。
文章中讨论了对桌面浏览器的支持。确实,它没有在结尾的单独部分,因此某些对角线阅读方式可能会错过它。
重申一遍:Mandy 的
clip-path
方法以及我的mix-blend-mode
方法目前在 Edge 中不受支持。如果您能花时间为它们投票以实现它们,我将不胜感激,因为这些功能的优先级确实取决于请求它们的人数。以下是链接:clip-path
投票为
mix-blend-mode
投票最后一种方法在 Edge 中有效。这里有一段在 Edge 中有效的 gif 录制
我一定会投票。
如果不再需要将 Internet Explorer 支持视为一个已死的问题,那将是件好事,但该浏览器尚未消亡。是的,它的使用量已大幅下降,但它仍然位居第二(1)。Firefox 的市场份额实际上比 Internet Explorer 还低。Edge 的市场份额甚至低于 Firefox 和 Internet Explorer,这篇文章中也考虑到了它。虽然不可否认 Edge 的使用量正在增长,但用户似乎并没有以一种能使其很快超过 Internet Explorer 使用量的速度采用它(2)。
Internet Explorer 正在消亡,但开发人员还没有摆脱它的魔爪。
http://www.netmarketshare.com
https://arstechnica.com/information-technology/2017/01/2016-on-the-web-firefox-fights-back-as-microsofts-share-slumps/
你好,
我想使用此功能来为放置在可能具有简单纯色或图像的背景元素之上的图标提供对比度。目的应该是始终具有“可见”图标,与背景中的内容无关。
可以做到吗?请考虑背景并不直接位于父项上,而是可以是任何东西...
mix-blend-mode
方法将在任何背景上起作用(不仅仅是直接的父级),只要您的图标的任何父级元素都没有建立堆叠上下文,它就会 强制隔离混合。如果图标本身是一个堆叠上下文(例如,如果它是绝对定位的),则没有问题:只要混合属性设置在与隔离相同的元素上,或者设置在树中更高位置的元素上即可。您可以对图标使用
drop-shadow
过滤器,以获得与文本阴影相同的效果。当然,您需要使用
@supports
测试来确保支持mix-blend-mode
和filter: drop-shadow(...)
,如果支持,则使用确保对比度的更简单方法,例如,在图标元素上使用纯色背景。这是一个很酷的效果,但在使用它之前,您应该考虑一件事。背景图像有多繁忙?
在简单的图像上,效果很好。如果您尝试在繁忙的图像上使用该效果(例如,哈雷戴维森摩托车的侧面),它会使文本难以阅读。
因此,这不是一个神奇的可访问性解决方案。如果客户能够更改图像(他们通常可以这样做),那么他们可以轻松地上传看起来像是来自“哪里是沃利”书籍的图像,并使文本完全无法阅读。
文本也必须足够粗。薄如纸的文本比粗文本更容易在背景图像中迷失。
我仍然认为,对比文本的最佳方法是使用对比轮廓(使用文本阴影)。
说实话,我个人仍然在使用它,因为它比其他任何方法都简单。由于没有艺术感,对我来说它更简单,风险也更低。在引入背景时,更容易搞砸。
在 Safari 中也不起作用(TP 29、10.2)。
很棒的工作。感谢分享。
至于浏览器支持,一个人必须从某个地方开始。没有人强迫您使用这些功能。如果大多数用户使用 IE 或任何不兼容的浏览器,也许它不适合您。您还可以通常找到一个 JS polyfill,直到那些用户升级。