圆角、渐变边框、毛玻璃的叠加实现与优化

实现一个圆角的效果最简单的方案便是border-raduis,同样的,实现渐变边框可以使用border-image。但两种属性的叠加并不会出现理想的效果,元素的边框呈现渐变效果,圆角却失效了。那如何使元素同时具备圆角和渐变边框的效果呢?

【能用】background-image

使用两个元素,底层元素使用渐变色背景,上层元素使用纯色背景,同时给两个元素设置圆角,从视觉上实现边框的效果

<div class="wrap">
  <div class='content'>
    “圆角渐变边框示例”是一个展示如何使用圆角和渐变效果来美化边框的案例。这个示例通过结合圆角的柔和视觉效果与渐变的色彩变化,展现出一种现代而富有层次感的设计风格。
  </div>
</div>
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.wrap {
  width: 300px;
  height: 150px;
  padding: 4px;
  margin: 25px auto;
  background-image: linear-gradient(112deg, #696bff 47%, #f0aeff 86%);
  border-radius: 16px 16px 4px 16px;
}

.content {
  width: 100%;
  height: 100%;
  padding: 8px;
  background-color: #fff;
  border-radius: 16px 16px 4px 16px;
}

虽然渐变边框和圆角的问题都解决了,但是正常情况下,内部圆角应该比外部圆角的尺寸要小,这里设置为相同的值,导致渐变边框在圆角的地方视觉上不协调。可以尝试减小内圆角弥补这个问题,但具体减小的尺寸不好确定。

image.png

【好用】background-image + background-clip

为了解决圆角尺寸不协调问题,在此引入background-clip。同样使用两个元素,底层元素使用渐变色背景,上层元素使用纯色背景,额外为上层元素添加透明边框,并设置background-clip: padding-box

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.wrap {
  width: 300px;
  height: 150px;
  margin: 25px auto;
  background-image: linear-gradient(112deg, #696bff 47%, #f0aeff 86%);
  border-radius: 16px 16px 4px 16px;
  position: relative;
}

.content {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  padding: 8px;
  background-color: #fff;
  border: 4px solid transparent;
  border-radius: 16px 16px 4px 16px;
  background-clip: padding-box;
}

以透明边框和background-clip的方式,使得内圆角不需要手动设定,纯色背景存在于边框内部,下层的渐变色因为透明边框的原因得以显现,在视觉上充当渐变边框。完美解决了手动设置内圆角,内外不协调问题。

image.png

【优化】background-image + background-clip + background-origin

background-image + background-clip的方案已经可以完美解决圆角渐变边框的问题了,但使用两个元素代码显得不够优雅,因此借助background-origin对代码进行简化。

<div class="wrap">
  “圆角渐变边框示例”是一个展示如何使用圆角和渐变效果来美化边框的案例。这个示例通过结合圆角的柔和视觉效果与渐变的色彩变化,展现出一种现代而富有层次感的设计风格。
</div>
.wrap {
  width: 300px;
  height: 150px;
  margin: 25px auto;
  padding: 8px;
  border: 4px solid transparent;
  background-clip: padding-box, border-box;
  background-origin: padding-box, border-box;
  background-image: linear-gradient(to right, #fff, #fff), linear-gradient(112deg, #696bff 47%, #f0aeff 86%);
  border-radius: 16px 16px 4px 16px;
}

使用padding-boxborder-box将纯色背景限制在padding及其以内,将渐变色限制在border及其以内,透明的border为渐变色预留空间,以两种不同的背景渲染方式叠加,实现一个节点圆角渐变边框,大大减少了代码量。需要注意的是必须先定义padding-box再定义border-box

image.png

【扩展1】添加毛玻璃效果

实现此功能,需要解决两个问题:

  1. 如何实现毛玻璃效果
  2. 如何让背景半透明

第一个问题不言而喻,使用滤镜backdrop-filter,不过backdrop-filterbackground-image并不能同时设置,因此毛玻璃滤镜需要独立于背景。对于背景半透明的效果,rgba必然是首选,但这里使用的是渐变色,故采用opacity赋予背景块半透明。这种方式处理后发现,文字也跟随背景有了半透明的效果,因此需要将文字独立于背景。最后,我们将滤镜加在文字节点上,使用伪元素实现背景块,背景块使用position: absolute;绝对定位,z-index: -1将背景块置于文字底部。

<div class="wrap">
  “圆角渐变边框示例”是一个展示如何使用圆角和渐变效果来美化边框的案例。这个示例通过结合圆角的柔和视觉效果与渐变的色彩变化,展现出一种现代而富有层次感的设计风格。
</div>
.wrap {
  position: absolute;
  top: 20px;
  left: 20px;
  width: 300px;
  height: 150px;
  padding: 8px;
  backdrop-filter: blur(5px);
  border-radius: 16px 16px 4px 16px;
}

.wrap::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 4px solid transparent;
  background-clip: padding-box, border-box;
  background-origin: padding-box, border-box;
  background-image: linear-gradient(to right, #fff, #fff), linear-gradient(112deg, #696bff 47%, #f0aeff 86%);
  border-radius: 16px 16px 4px 16px;
  opacity: 0.7;
  z-index: -1;
}

图片中间的元素同时具备了圆角、渐变边框和毛玻璃的效果,唯一美中不足是opacity将背景色块的颜色变浅了,不能接受的话就只能用SVG去实现了。

image.png

【扩展2】封装为 scss 方法

以上的方案已经基本实现了我们的需求,但页面中广泛应用时,需要频繁复制粘贴,造成了代码冗余,因此我们借助 scss 将圆角渐变边框封装为一个通用方法linear-gradient-bg,通过参数控制边框颜色、圆角、宽度等

@mixin linear-gradient-bg(
  $innerBg: linear-gradient(to right, #fff, #fff),
  $borderBg: linear-gradient(112deg, #696bff 47%, #f0aeff 86%),
  $borderWidth: 4px,
  $borderRadius: 16px 16px 4px 16px,
  $backdropFilter: blur(5px),
  $opacity: 0.7,
  $boxSizing: content-box
) {
  position: relative;
  backdrop-filter: $backdropFilter;

  &::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    @if $boxSizing == content-box {
      width: 100%;
      height: 100%;
    } @else {
      width: calc(100% - $borderWidth * 2);
      height: calc(100% - $borderWidth * 2);
    }
    border: $borderWidth solid transparent;
    background-clip: padding-box, border-box;
    background-origin: padding-box, border-box;
    background-image: $innerBg, $borderBg;
    border-radius: $borderRadius;
    opacity: $opacity;
    z-index: -1;
  }
}

接下来我们使用linear-gradient-bg这个 scss 方法实现一下圆角渐变边框的功能

<div class="wrap">
  “圆角渐变边框示例”是一个展示如何使用圆角和渐变效果来美化边框的案例。这个示例通过结合圆角的柔和视觉效果与渐变的色彩变化,展现出一种现代而富有层次感的设计风格。
</div>
.wrap {
  @include linear-gradient-bg();
  position: absolute;
  top: 20px;
  left: 20px;
  width: 300px;
  height: 150px;
  padding: 8px;
  border-radius: 16px 16px 4px 16px;
}

image.png

通过封装 scss 方法的方式,使用时仅需@include linear-gradient-bg();一行代码即可实现圆角渐变边框的功能。在调用这个方法时,还可以通过参数控制边框样式,例如要修改渐变边框颜色、圆角属性,仅需在调用时传入自定义$borderBg$borderRadius即可

.wrap {
  @include linear-gradient-bg(
    $borderBg: linear-gradient(112deg, #65c9eb 47%, #6bd750 86%),
    $borderRadius: 16px
  );
  position: absolute;
  top: 20px;
  left: 20px;
  width: 300px;
  height: 150px;
  padding: 8px;
  border-radius: 16px;
}

image.png

【扩展3】使用 SVG 实现

上述方案中为了实现毛玻璃的效果,我们不得不为背景色设置opacity,让背景变得半透明,但这样同时导致了边框颜色变淡。进一步解决这个问题,我们采用 SVG 重新实现此功能

<div className="wrap">
  “圆角渐变边框示例”是一个展示如何使用圆角和渐变效果来美化边框的案例。这个示例通过结合圆角的柔和视觉效果与渐变的色彩变化,展现出一种现代而富有层次感的设计风格。
  
  <svg width="100%" height="100%">
    <!-- 定义渐变 -->
    <defs>
      <linearGradient id="gradient1" x1="0%" y1="0%" x2="100%" y2="0" gradientTransform="rotate(112deg)">
        <stop offset="47%" style={{ stopColor: '#696bff', stopOpacity: 1 }} />
        <stop offset="86%" style={{ stopColor: '#f0aeff', stopOpacity: 1 }} />
      </linearGradient>
    </defs>

    <!-- 绘制圆角矩形,应用渐变边框 -->
    <rect
      x="2"
      y="2"
      width="calc(100% - 4px)"
      height="calc(100% - 4px)"
      rx={16}
      fill="none"
      stroke="url(#gradient1)"
      strokeWidth="4"
    />
  </svg>
</div>
.wrap {
  position: absolute;
  top: 20px;
  left: 20px;
  width: 300px;
  height: 150px;
  padding: 8px;
  border-radius: 16px;
  backdrop-filter: blur(5px);
}
svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
}

image.png

可以看出 SVG 的方案,相比于 css 没有颜色偏差,毛玻璃效果也更加明显,缺点是书写起来较为复杂,如果项目中使用类似 postcss 对 px 进行转换的话,还需要手动针对 SVG 的数值做对应的处理。

补充:rect 的 x、y 需要设置为边框宽度的一半,width、height 也需要减去一个边框宽度。下面引用 MDN 中的图,可以看出边框是以设置点为中心,两侧均分,如果x、y设置为0,有一半边框会丢失

image.png

至此已经通过多种方式实现了圆角渐变边框的功能,优先推荐使用 scss 封装方法的方案,这种方案更简洁、复用性更强,项目中如果没有集成 scss 则使用background-image + background-clip + background-origin的方案。如果需要毛玻璃效果,且对精度要求很高,颜色不能有偏差,则使用 SVG 的方案。

posted @ 2024-09-19 20:59  寒沁  阅读(24)  评论(0)    收藏  举报  来源