一个星期天的早上,我比平时早起了一些,因为手机不断地嗡嗡作响。 我伸手拿起手机,点击进入 Facebook Messenger,加入了聊天。 不久后,我的注意力从实际的对话转移到了包含对话的消息气泡的 funky 渐变效果上。 让我向您展示我的意思

这是 Messenger 的一项新功能,它允许您为聊天消息的背景选择渐变而不是纯色。 它目前在移动应用程序以及 Facebook 网站上可用,但尚未在 Messenger 网站上可用。 渐变显示为“固定”,因此聊天气泡在垂直滚动时会显示出不同的背景颜色。
我认为这看起来像是可以在 CSS 中完成的,所以… _挑战接受!_
让我们一起回顾一下我的思路,当我尝试重新创建它并解释用于使其工作的 CSS 功能时。 此外,我们将了解 Facebook _实际上_ 是如何实现它的(剧透警告:不是我那样做的),以及两种方法的比较。
动手实践
首先,让我们再看一下示例,看看我们到底要实现什么。
总的来说,我们有一个相当标准的消息布局:消息被划分为从上到下的气泡,我们的气泡在右边,聊天中的其他人气泡在左边。 左边的气泡都具有灰色背景颜色,但右边的气泡看起来好像共享相同的固定背景渐变。 基本上就是这些!
步骤 1:设置布局
这部分非常简单:让我们将消息排列在一个有序列表中,并应用一些基本 CSS 使其看起来更像一个实际的消息应用程序
<ol class="messages">
<li class="ours">Hi, babe!</li>
<li class="ours">I have something for you.</li>
<li>What is it?</li>
<li class="ours">Just a little something.</li>
<li>Johnny, it’s beautiful. Thank you. Can I try it on now?</li>
<li class="ours">Sure, it’s yours.</li>
<li>Wait right here.</li>
<li>I’ll try it on right now.</li>
</ol>
谈到将消息划分为左右两部分时,我的第一反应是使用浮动。 我们可以对左边的消息使用 float: left
,对右边的消息使用 float: right
,使它们粘贴到不同的边缘。 然后,我们将在每条消息上应用 clear: both
以使它们堆叠起来。 但是,有一种更现代的方法——Flexbox!
我们可以使用 Flexbox 通过 flex-direction: column
将列表项垂直堆叠,并告诉所有子项粘贴到左边缘(或“将 flex 子项的交叉开始边缘与行的交叉开始边缘对齐”,如果您更喜欢技术术语)。 然后,我们可以通过在它们上设置 align-self: flex-end
来覆盖单个 flex 项的 align-items
值。
什么,你是说你无法根据这个可视化代码? 好的,这就是它的样子
.messages {
/* Flexbox-specific styles */
display: flex;
flex-direction: column;
align-items: flex-start;
/* General styling */
font: 16px/1.3 sans-serif;
height: 300px;
list-style-type: none;
margin: 0 auto;
padding: 8px;
overflow: auto;
width: 200px;
}
/* Default styles for chat bubbles */
.messages li {
background: #eee;
border-radius: 8px;
padding: 8px;
margin: 2px 8px 2px 0;
}
/* Styles specific to our chat bubbles */
.messages li.ours {
align-self: flex-end; /* Stick to the right side, please! */
margin: 2px 0 2px 8px;
}
在这里和那里添加一些填充和颜色,这已经足够相似,可以继续进行有趣的步骤了。
步骤 2:让我们为事物着色!
关于渐变的初始想法实际上来自 Matthias Ott 的这条推文(Chris 在另一篇文章中重新创建了它)
这是一个糟糕的技巧,在文本之上有一个伪元素,混合混合模式在 IE/Edge 中不起作用,但是:是的,可以使用 CSS 来实现! 😅https://#/FLKGvd1YoI
— Matthias Ott (@m_ott) 2018 年 12 月 3 日
这里的关键线索是 mix-blend-mode
,它是一个 CSS 属性,允许我们控制元素的内容如何与后面的内容混合。 它是一项已在 Photoshop 和其他类似工具中存在一段时间的功能,但对网络来说是相当新的。 有一个关于该属性的 年鉴条目,它解释了所有可能的值。
其中一个值为 screen
:它获取背景和前景像素的值,反转它们,将它们相乘,然后再次反转它们。 这将产生一种比原始背景颜色更亮的顏色。
描述可能看起来有点令人困惑,但它本质上意味着,如果背景是单色的,则在背景为黑色的地方,将完全显示前景像素,而在背景为白色的地方,白色保持不变。

mix-blend-mode: screen;
,我们将看到更多前景,因为背景更暗。因此,为了达到我们的目的,背景将是聊天窗口本身,而前景将包含一个元素,该元素具有设置为背景的所需渐变,并放置在背景之上。 然后,我们将适当的混合模式应用于前景元素,并重新设置背景样式。 我们希望背景在我们要显示渐变的地方为黑色,而在其他地方为白色,因此我们将通过为气泡设置纯黑色背景和白色文字来设置它们样式。 哦,还要记住在前景元素中添加 pointer-events: none
,以便用户可以与底层文本进行交互。
此时,我还稍微更改了原始 HTML。 整个聊天是在一个额外的容器中的一个包装器,允许渐变在聊天的可滚动部分上保持“固定”。
.messages-container:after {
content: '';
background: linear-gradient(rgb(255, 143, 178) 0%, rgb(167, 151, 255) 50%, rgb(0, 229, 255) 100%);
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
mix-blend-mode: screen;
pointer-events: none;
}
.messages li {
background: black;
color: white;
/* rest of styles */
}
结果看起来像这样

步骤 3:将某些消息排除在渐变之外
现在,渐变正在文本气泡所在的地方显示! 但是,我们只希望它在_我们_的气泡上显示——即沿着右边缘的气泡。 如何实现这一目标的提示隐藏在 MDN 的 mix-blend-mode
属性描述 中
mix-blend-mode
CSS 属性设置元素的内容应如何与元素的父元素的内容和元素的背景混合。
没错! 背景。 当然,该效果只考虑位于当前元素后面且具有较低堆叠顺序的 HTML 元素。 幸运的是,可以使用 z-index
属性轻松更改元素的堆叠顺序。 因此,我们所要做的就是让左边聊天气泡的 z-index
比前景元素的 z-index
更高,它们将被提升到前景元素之上,不受 mix-blend-mode
的影响! 然后,我们可以根据自己的意愿设置它们样式。

让我们谈谈浏览器支持
在撰写本文时,mix-blend-mode
在 Internet Explorer 和 Edge 中完全不受支持。 在这些浏览器中,渐变被放置在整个聊天之上,其他人的气泡出现在渐变之上,这不是理想的解决方案。
这些浏览器支持数据来自 Caniuse,它包含更多详细信息。 数字表示浏览器从该版本开始支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
41 | 32 | 否 | 79 | TP |
移动/平板
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 127 | 127 | 18.0 |
因此,这就是我们在不支持的浏览器中获得的结果

mix-blend-mode
的浏览器如何呈现聊天。幸运的是,所有支持 mix-blend-mode
的浏览器也支持 CSS 功能查询。 使用它们可以先为不支持的浏览器编写后备样式,然后为支持它们的浏览器包含花哨的效果。 这样,即使用户看不到完整的效果,他们仍然可以看到整个聊天并与之交互

这是具有完整效果和后备样式的最终 Pen
查看 Pen
在 CSS 中使用 Facebook Messenger 式渐变颜色 by Stepan Bolotnikov (@Stopa)
在 CodePen 上。
现在让我们看看 Facebook 是如何做到的
事实证明,Facebook 的解决方案几乎与我们在这里讨论的内容相反。 他们不是将渐变放置在聊天之上并在其中打孔,而是将渐变作为固定背景图像应用于整个聊天。 聊天本身充满了许多带有白色背景和边框的空元素,除了渐变应该可见的地方。
Facebook Messenger React 应用程序渲染的最终 HTML 非常冗长且难以导航,因此我重新创建了一个简化的示例来说明它。 许多空 HTML 元素可以用伪元素代替。
查看 Pen
在 CSS 中使用 Facebook Messenger 式渐变颜色:Facebook 的方法 by Stepan Bolotnikov (@Stopa)
在 CodePen 上。
正如您所见,最终结果看起来类似于mix-blend-mode
解决方案,但增加了少量额外的标记。此外,他们的方法为图像和表情符号等丰富内容提供了更大的灵活性。如果背景不是单色,mix-blend-mode
方法实际上不起作用,而且我还没有找到一种方法将内部内容“提升”到渐变之上,或者以其他方式克服此限制。
由于此限制,在实际聊天应用程序中使用 Facebook 的方法更为明智。尽管如此,我们使用mix-blend-mode
的解决方案展示了一种有趣的方式来使用现代网页设计中最不为人知的 CSS 属性之一,希望它能为您提供一些关于如何使用它的想法!
很酷的东西!令人遗憾的是 Facebook 选择了标记混乱,但考虑到他们的“赞助商”解决方案,我并不感到惊讶。
我使用
background-position: fixed
制作了一个变体,它可以工作,但灵活性较差,因为您必须指定大小(为方便起见,我使用了 SCSS 变量):https://codepen.io/chriskirknielsen/pen/bZEZjb从好的方面来说,浏览器支持更好(我假设?),如果您想让消息容器占据整个屏幕(或任何设定大小),您可以使用
100vw/vh
。background-attachment: fixed
怎么样? 它和上面那个一样吗? 也许固定会带来性能问题https://codepen.io/equinusocio/pen/PLZLxr?editors=1100
我选择了
background-attachment: fixed
。但我没有使用 flex,而是margin-left: auto
ed “入站”气泡。哦,等等。它在移动设备上并不完全有效。渐变扩展了文档的长度,而不仅仅是视窗。并不丑陋,但也不是我们想要的结果。
我和上面的人有同样的想法
我曾经读过,向固定元素的父项添加一个转换可以重新创建一个根锚点,但遗憾的是,它会将每个聊天气泡作为根,而不是周围的元素(我想知道容器查询能否解决这个问题)。
只要无法做到(将固定的背景锚定到父元素而不是文档),聊天包装器就需要设置
background-size
和background-position
不涉及代码,但用汤米·威索的《房间》来解释马克·扎克伯格的 Facebook 的一些东西,这很有道理。我喜欢它!
关于建议方法的一个有趣的小细节,在非 Windows 计算机上可能没有注意到(或可见):它也会将滚动条与背景渐变混合在一起,使其具有相同的效果。这是值得注意的 CSS 混合模式,我从未想过。
感谢您的有趣文章!无论如何,在您的方法中,滚动条也被混合在一起了。对此有什么额外的调整吗?