原文链接:www.smashingmagazine.com/2024/01/css…
阴影在 CSS中相当简单:声明 box-shadow 属性,设置阴影偏移量,定义跨度并为其提供颜色。这是为原本扁平化的设计增加深度的好方法!从阴影中汲取灵感,作者 Yair Even Or创造了同样的东西,只是用模糊效果代替了阴影。请继续阅读,逐步了解如何使用mask、渐变和常用的backdrop-filter 属性组合在一起。
想象一下 box-shadow ,对于模糊效果,一个元素的背景在该元素周围模糊,逐渐降低模糊的强度。我在尝试提高弹出窗口在黑暗区域上的对比度时有了这个想法,在设计方面,弹出窗口的 a box-shadow 没有多大意义。然后我在想,是否还有其他什么方法可以产生良好的对比效果?突然间,我萌生了在物体周围逐渐模糊效果的想法。
假设我们有一个 box-blur 属性,或者某种 blur 关键字,我们可以设置 box-shadow 阴影的方式 inset ,那就太棒了。不幸的是,CSS 没有这样的属性。但是由于 CSS 很棒且灵活,我们仍然可以通过组合一些 CSS 功能来实现这样的效果。
接下来,我将向大家展示的是我创造这种效果的思考过程。有时,我发现知道即将发生的事情比蜿蜒曲折的叙述更容易。所以,对于那些像我一样想直接进入这个过程的人来说,这就是我的方法。
从标记开始
该效果的处理方式是将其应用于某个元素的 ::before 伪元素,例如popup/dialog/popover/tooltip等。这些是这种效果的常见“目标”。我认为在这里使用伪元素是一个很好的方法,因为这意味着我们可以在技术上将样式范围限定为伪元素,并在没有任何 HTML 更改的情况下对其他元素产生效果上的影响。
<!-- This is literally it for this demo -->
<div></div>
您可以为元素提供一个类,无论您喜欢什么尺寸,在其中插入内容和其他子元素,或者使用完全不同的元素。HTML 不是我们要实现效果的主要关注目标。
定位伪元素
我们希望 ::before 伪元素占据我们用于此特定演示的 <div> 元素的整个区域。我们希望它覆盖整个区域,甚至溢出这个区域,因为我们实现模糊效果是在整个区域甚至实在整个区域之外的部分,这样在超出的部分更好的看到模糊效果。
::before {
content: '';
/* Make sure the parent element is at least relatively positioned to contain the pseudo-element. */
position: absolute;
/* The blur size should be anything below `0` so it will extend to the outside. */
inset: -100px;
/* This layer is positioned between the parent element and page background. */
/* Make sure this value is one below the `z-index` of the parent element. */
z-index: -1;
}
代码注释阐明了关键部分。必须为 content 属性设置一个空字符串,方便 ::before 可以呈现要呈现的部分,然后我们通过为其提供绝对定位将其从文档流中取出。这允许我们确定 inset 元素的位置,并最终像在 box-shadow 属性上一样设置模糊效果方向 - 只是我们用来 inset 控制它的大小。我们想要一个负 inset 值,该值越小,效果越远。
到目前为止,我们已经为这种效果奠定了基础。目前还没有看到什么效果。接下来,有趣的部分要开始了!
使用透明渐变进行遮罩
从技术上讲,渐变是由浏览器生成的图像,可以用作 CSS 蒙版来隐藏元素的某些部分以创建各种形状。您可能已经看过一些相关的 Smashing Magazine 文章,其中展示了 CSS mask,例如 Temani Afif 的这篇文章。
我们希望效果更强,更接近物体,并且随着距离物体越来越远,强度会逐渐减弱,在这种情况下,这是完美的
我们将使用两个渐变:一个是水平的,另一个是垂直的。我之所以选择这条路线,是因为它模仿了一个粗糙的矩形形状,向边缘逐渐淡出。
正如我所说,透明度是关键。两个渐变都是以 transparent 开始,然后过渡到 black ,直到结束之前,它们回到 transparent 淡出。请记住,这些渐变是蒙版而不是背景图像,因此它们是在 mask 属性上声明的,该属性控制应呈现的像素及其不透明度。
mask:
linear-gradient(to top, transparent 0%, black 25% 75%, transparent 100%),
linear-gradient(to left, transparent 0%, black 25% 75%, transparent 100%);
- 垂直渐变 (
to top) 创建从底部的透明到中间的黑色,然后回到顶部的透明的淡入淡出。 - 水平渐变 (
to left) 产生从右侧的透明到中间的黑色,然后回到左侧的透明的淡入淡出。
这种双梯度方法对黑色区域进行定位,使它们合并,从而创建矩形形状的粗略基线,该基线将在下一步中进行细化。该 mask 属性最好声明为先加前缀,然后不加前缀,以涵盖更多浏览器的支持:
-webkit-mask:
linear-gradient(to top, transparent 0%, black 25% 75%, transparent 100%),
linear-gradient(to left, transparent 0%, black 25% 75%, transparent 100%);
mask:
linear-gradient(to top, transparent 0%, black 25% 75%, transparent 100%),
linear-gradient(to left, transparent 0%, black 25% 75%, transparent 100%);
使用 mask-composite 属性进行优化
该 mask-composite 属性是 CSS 遮罩模块的一部分,支持对遮罩内容的混合进行像素级控制,从而实现复杂的合成。
此属性的 source-in 值对于我们所追求的效果非常有用,因为它告诉浏览器只保留蒙版的重叠区域,因此只有包含两个(上面提到的)渐变的像素才会被渲染。这将锁定一个矩形形状,然后可以将其应用于任何没有或中等弯曲角的 DOM 元素 ( border-radius )。
逐渐模糊背景
现在我们有了一个可以使用的mask,我们需要做的就是使用它。 backdrop-filter CSS 属性可以使用 blur() 函数模糊呈现在元素“后面”的任何内容:
::before {
/* etc. */
backdrop-filter: blur(10px);
}
该值越大,模糊越强烈。我是任意使用的 10px 。事实上,我们可以稍后对这些东西进行更改,以使实现更加灵活且易于配置。
但是等等!事实证明,Safari 需要一个以供应商为前缀的 backdrop-filter 版本才能让它在那里工作:
::before {
/* etc. */
-webkit-backdrop-filter: blur(10px); /* Required for Safari */
backdrop-filter: blur(10px);
}
注意:最好在无前缀变体之前声明带前缀的属性,以便它们作为(尚)不支持它们或其实现不同的浏览器的回退。
协同阴影
我认为添加一个轻微的半不透明的黑色 box-shadow 来覆盖模糊区域会给效果带来一点额外的深度。唯一的问题是,您需要将其添加到元素本身中,而不是将其 添加到::before 伪元素中:
div {
box-shadow: 0 0 40px #00000099;
}
不过,这完全是可选的。
将所有结合在一起
当我们将所有内容组合在一起时,微光效果就这样出现了。
/* This can be set on the ::before pseudo of the element it is applied to. */
::before {
content: '';
/* This layer is positioned between some element and its background. */
position: absolute;
/* This should not affect the contents of the container. */
z-index: -1;
/* The blur size should be anything below `0` so it will extend to the outside. */
inset: -100px;
/* The blur effect */
-webkit-backdrop-filter: blur(10px); /* Required for safari */
backdrop-filter: blur(10px);
/* A mask fades the blur effect, so it gets weaker. */
/* towards the edges, further from the container box. */
/* (The fill color is irrelevant, so "red" is used as it's the shortest color name.) */
mask:
linear-gradient(
to top,
transparent 0%,
red 100px calc(100% - 100px),
transparent 100%),
linear-gradient(
to left,
transparent 0%,
red 100px calc(100% - 100px),
transparent 100%);
/* This merges the masks above so only the overlapping pixels are rendered. */
/* This creates the illusion of a fade-out mask. */
mask-composite: intersect;
-webkit-mask-composite: source-in; /* Required for Safari */
}
最后的演示,再一次
我还准备了一个简化版本,代码最少,没有 CSS 变量,更易于阅读和重新使用。