使用蒙版创建花哨的 CSS 边框(锯齿形、波浪形等等)

Avatar of Temani Afif
Temani Afif

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 的免费积分!

您是否尝试过制作带有重复锯齿图案的 CSS 边框?例如,网站上一个彩色区域与另一个不同颜色区域的交界处,不是一条直线,而是角度锯齿、圆形凸起或波浪。您可以使用多种方法来创建这种 CSS 边框,从使用 background-image 开始。但我们可以使用更现代、更具程序性的方法来实现。在这篇文章中,我们将探讨一些现代 CSS 蒙版技术来实现这种外观。

不过,在我们深入技术细节之前,让我们先看一下我们要构建的内容。我做了一个 CSS 边框生成器,您可以在几秒钟内轻松生成任何类型的边框,并获取 CSS 代码。

您看到那个了吗?使用 CSS mask 属性 和一些 CSS 渐变,我们就可以获得响应式且美观的边框,所有这些都通过 CSS 本身实现。不仅如此,这种效果还可以应用于任何可以有各种颜色的元素(例如图像、渐变等)。我们无需额外的元素、伪元素或来自无处的魔数即可实现这一切!

太好了!我所要做的就是复制/粘贴代码,就完成了!

确实,但了解逻辑有助于您在需要时手动调整代码。

蒙版事物

由于我们所有的效果都依赖于 CSS mask 属性,让我们快速回顾一下它的工作原理。直接来自 规范

将蒙版应用于图形对象的效果就像将图形对象通过蒙版绘制到背景上一样,从而完全或部分地遮蔽图形对象的部分。

如果我们检查 mask 属性的正式语法,我们可以看到它接受 <image> 作为值,这意味着图像的 URL 或颜色渐变。我们将使用渐变。让我们从基本示例开始

在这个演示的第一个示例中,使用了渐变来使图像看起来像是逐渐消失。与此同时,第二个示例也使用了渐变,但它不是在颜色之间进行平滑过渡,而是使用了 硬色停顿 来隐藏(或遮蔽)图像的一半。第二个示例说明了我们将用于创建花哨边框的技术。

哦,而且 CSS mask 属性可以接受多个渐变,只要它们用逗号隔开。这意味着我们对遮蔽图像的其他部分有更大的控制权。

乍一看,显示多个遮蔽渐变的示例可能有点棘手,但其原理与在 background 属性上应用多个渐变相同。但我们不是使用与页面背景融合的颜色,而是对图像的隐藏部分使用“透明”黑色值 (#0000),对可见部分使用全黑 (#000)。

就是这样!现在我们可以处理花哨的边框了。

锯齿形 CSS 边框

正如我们在文章开头的视频中看到的,该生成器 可以在一侧、两侧或所有侧面上应用边框。让我们从使用逐步插图的底部开始。

  1. 我们首先在中间添加一个具有特定尺寸的 conic-gradient()
  2. 接下来,我们重复该渐变(通过删除 no-repeat),我们已经看到锯齿形!
  3. 众所周知,渐变在创建锯齿状边缘(尤其是在 Chrome 中)时会遇到抗锯齿问题。为了避免这种情况,我们在颜色之间添加了一个轻微的过渡,将 blue 90deg, green 0 更改为 green, blue 1deg 89deg, green 90deg
  4. 最后,我们将所有内容都放到 mask 属性中!

我们可以从这些步骤中提取两个变量来定义我们的形状:大小 (40px) 和角度 (90deg)。以下是我们可以使用占位符表示这些变量的方式。我将使用 JavaScript 来将这些变量替换为它们的值。

mask:
  conic-gradient(
    from {-angle/2} at bottom,
    #0000, #000 1deg {angle - 1} ,#0000 {angle}
  ) 50%/{2*size*tan(angle/2)} 100%;

我们可以使用 CSS 自定义属性来表示大小和角度,但目前不支持三角函数。将来,我们可以执行类似的操作

--size: 40px;
--angle: 90deg;
mask:
  conic-gradient(
    from calc(var(--angle)/-2) at bottom,
    #0000, #000 1deg calc(var(--angle) - 1deg), #0000 var(--angle)
  ) 50%/calc(2*var(--size)*tan(var(--angle)/2)) 100%;

与底部边框类似,顶部边框将具有几乎相同的代码,只是一些调整

mask:
  conic-gradient(
    from {180deg - angle/2} at top,
    #0000, #000 1deg {angle - 1}, #0000 {angle}
  ) 50%/{2*size*tan(angle/2)} 100%;

我们将 bottom 替换为 top,然后将渐变的旋转更新为 180deg - angle/2 而不是 -angle/2。就这么简单!

这是我们可以用于剩余侧面的模式,例如左侧

mask:
  conic-gradient(
    from {90deg - angle/2} at left,
    #0000, #000 1deg {angle - 1}, #0000 {angle}
  ) 50%/100% {2*size*tan(angle/2)};

…以及右侧

mask:
  conic-gradient(
    from {-90deg - angle/2} at right,
    #0000, #000 1deg {angle - 1}, #0000 {angle}
  ) 50%/100% {2*size*tan(angle/2)};

让我们为一次应用于两侧的边框创建边框。我们实际上可以重用相同的代码。要获得顶部和底部边框,我们只需将顶部和底部边框的代码组合起来即可。

mask:
  conic-gradient(
    from {-angle/2} at bottom,
    #0000, #000 1deg {angle - 1}, #0000 {angle}
  ) bottom/{2*size*tan(angle/2)} 51% repeat-x;
  conic-gradient(
    from {180deg - angle/2} at top, 
    #0000, #000 1deg {angle - 1}, #0000 {angle}
  ) top   /{2*size*tan(angle/2)} 51% repeat-x;

同样,在同时应用于左侧和右侧的边框时也是如此

mask:
  conic-gradient(
    from {90deg - angle/2} at left,
    #0000, #000 1deg {angle - 1}, #0000 {angle}
  ) left /51% {2*size*tan(angle/2)} repeat-y,
  conic-gradient(
    from {-90deg - angle/2} at right,
    #0000, #000 1deg {angle - 1}, #0000 {angle}
  ) right/51% {2*size*tan(angle/2)} repeat-y;

那么,如果我们想一次性将边框应用于所有侧面,我们只需要将所有渐变加在一起,对吧?

没错!我们有四个锥形渐变(每边一个)和一个中间的 linear-gradient()。我们设置了一个固定角度,等于 90deg,因为它是唯一一个能够在没有奇怪的重叠的情况下产生更美观的角的设置。请注意,我还在使用 space 而不是 repeat-xrepeat-y 来避免出现以下这种情况下的糟糕结果

调整具有四边配置的容器的大小

圆角 CSS 边框

现在让我们来处理圆角边框!

哦,不!又是一个带有大量计算的长篇解释?

并非如此!这里没什么好解释的。我们从锯齿形示例中获取所有内容,并将 conic-gradient() 更新为 radial-gradient()。这甚至更容易,因为我们无需处理任何角度,只需处理大小变量。

以下是针对一侧的插图,说明我们将锯齿形边框切换为圆角边框所需要做的微小调整

同样,我只做了将 conic-gradient() 替换为以下内容(使用大小占位符)

mask: radial-gradient({size} at bottom,#0000 98%,#000) 50% / {1.85*size} 100%;

魔法数字 1.85 和 98% 背后的逻辑是什么?

从逻辑上讲,我们应该使用 100% 而不是 98% 来获得一个与背景区域边缘相切的圆圈;但同样,这是抗锯齿问题以及那些锯齿状边缘。我们使用一个稍微小一点的值来防止出现奇怪的重叠。

1.85 值更像是个人喜好,而不是别的什么。我最初使用 2,这是得到完美圆圈的逻辑值,但结果看起来不太好,因此较小的值会在圆圈之间创建更无缝的重叠。

以下是区别

现在我们需要像处理锯齿形 CSS 边框一样,将此操作复制到其他侧面,您猜对了?对于我们想要拥有顶部/底部或左侧/右侧版本的情况,我们也需要一个渐变。

唯一需要多个渐变的情况是所有侧面的配置。与锯齿形边框类似,我们必须使用四个径向渐变和一个线性渐变,但我必须引入 CSS clip-path 属性来更正角处的重叠问题。您可以在以下演示中看到使用和不使用 clip-path 之间的区别

这是一个八点路径,用于切割角

clip-path: polygon(
   {2*size} 0,calc(100% - {2*size}) 0,
   100% {2*size},100% calc(100% - {2*size}),
   calc(100% - {2*size}) 100%,{2*size} 100%,
   0 calc(100% - {2*size}),0 {2*size}
);

波浪形 CSS 边框

对于这种边框,无论侧面配置如何,我们始终需要两个渐变。我们使用径向渐变来创建圆圈的重复图案,并使用线性渐变来覆盖它们,并仅显示我们想要的侧面。

以下是一个演示,说明了其中的一些情况

请注意我如何使用 roundspace 值。这样可以确保我们不会切断任何圆圈,并且还可以避免依赖更多渐变。同样,1.85 值是个人喜好值。

波浪形 CSS 边框

波浪形边框是前面两种边框的组合。以下是一个插图,帮助您了解我们如何构建底部波浪。

我们将该形状重复到底部,就完成了。

mask: 
  radial-gradient({size} at 75% 100%,#0000 98%,#000) 50% calc(100% - {size})/{4*size} 100% repeat-x,
  radial-gradient({size} at 25% 50% ,#000 99%,#0000 101%) bottom/{4*size} {2*size} repeat-x;

我们对其他侧面也执行与锯齿形和圆角 CSS 边框相同的操作。我们只需要更新一些变量,就可以在每侧获得不同的波浪。

显示每侧的部分 CSS。您可以在 生成器 中找到完整的代码。

在所有四侧应用波浪形 CSS 边框会怎样?总共有 8 个渐变吗?"

不,因为没有演示如何在所有四边应用波浪形边框。我找不到能够在角落产生良好效果的渐变组合。也许有读者知道好的方法?😉

这里我们所做的是一个简单的波浪形边框案例。我在另一篇文章中详细介绍了如何创建复杂的波浪形形状。

这简直是边框级别的精彩内容!

所以,您了解了我酷炫的小型在线 CSS 边框生成器 的里里外外!当然,您可以使用它生成的代码,一切都会很好 - 但现在您拥有了使其工作的秘诀。

具体来说,我们看到了如何使用渐变来遮蔽元素的一部分。然后我们着手使用多个渐变来从这些渐变 CSS 遮罩中创建特定形状。结果是可以用在元素边缘的图案,创造出您可能需要使用background-image才能实现的精美边框外观。唯一的区别是,这种方法只需替换一些值就可以改变外观,而无需替换整个光栅图像文件或其他东西。