CSS实现模糊微光效果(译)

avatar

原文链接: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 变量,更易于阅读和重新使用。