DIV 上的 CSS 动画渐变边框

问题描述

我正在尝试创建一个加载 DIV,它的边框看起来像一个不确定的进度环形微调器。

基于 https://css-tricks.com/gradient-borders-in-css/ 上的示例之一,我非常接近

当边框不旋转时这很棒。当您在 border 元素中设置 :before 以匹配 border 元素中的透明 gradient-Box 时,静态渐变边框看起来很完美。

但是,一旦添加了动画,因为整个 :before 元素都在旋转,您会得到一个非常奇怪的效果 - 如下例所示。

.gradient-Box {
  
  display: flex;
  align-items: center;
  width: 90%;
  margin: auto;
  max-width: 22em;

  position: relative;
  padding: 30% 2em;
  Box-sizing: border-Box;

  border: 5px solid blue;
  color: #FFF;
  background: #000;
  background-clip: padding-Box; /* !importanté */
  border: solid 5px transparent; /* !importanté */
  border-radius: 1em;

}

.gradient-Box:before {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: -1;
    margin: -35px; /* !importanté */
    border-radius: inherit; /* !importanté */
    background: conic-gradient(#0000ff00,#ff0000ff);
    -webkit-animation: rotate-border 5s linear infinite;
    -moz-animation: rotate-border 5s linear infinite;
    -o-animation: rotate-border 5s linear infinite;
    animation: rotate-border 3s linear infinite;
}

@keyframes rotate-border {
    to {
        transform: rotate(360deg);
    }
}

html { height: 100%; background: #000; display: flex; }
body { margin: auto; }
<!DOCTYPE HTML>
<html>
<head>
<Meta charset="utf-8">
<title>Loading DIV Test</title>
</head>
<body>

<div id="loadingBox" class="gradient-Box">
<p>Loading.</p>
</div>

</body>

我试过玩溢出:隐藏;但边框只是消失了.. 有什么方法可以“屏蔽” :before 元素,使加载 Div 后面的任何内容仍然可见,以便边框保持其预期宽度?

基本上,我的目标是使 border 中的颜色渐变旋转以产生旋转/旋转边缘的效果

解决方法

嗨,这是您要找的吗?

我所做的是添加了一个新的 div,它将作为“掩码”以及用于掩码和加载框的容器 div。

然后我将遮罩的大小设置为比您的可见区域大一点,使其成为透明背景,然后给它一个与背景颜色相同的大轮廓,以有效地遮住边框。然后我摆弄了面具的 z-indexs、loadingbox 和之前的。我还在 mask 上添加了一些实际边框,将其框成一个漂亮的形状。

看看:

.gradient-box {
  
  display: flex;
  align-items: center;
  width: 90%;
  margin: auto;
  max-width: 22em;

  position: relative;
  padding: 30% 2em;
  box-sizing: border-box;

  border: 5px solid blue;
  color: #FFF;
  background: #000;
  background-clip: padding-box; /* !importanté */
  border: solid 5px transparent; /* !importanté */
  border-radius: 1em;

}

.gradient-box:before {
    content: '';
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: -3;
    margin: -35px; /* !importanté */
    border-radius: inherit; /* !importanté */
    background: conic-gradient(#0000ff00,#ff0000ff);
    -webkit-animation: rotate-border 5s linear infinite;
    -moz-animation: rotate-border 5s linear infinite;
    -o-animation: rotate-border 5s linear infinite;
    animation: rotate-border 3s linear infinite;
}

@keyframes rotate-border {
    to {
        transform: rotate(360deg);
    }
}

html { height: 100%; background: #000; display: flex; }
body { margin: auto; }

.mask {
  position: absolute;
   box-sizing: border-box;
background-color: transparent; 
 outline: 65px solid black;
height: 100%;
  width: 100%;
  border: 2px solid black;
  border-left: 7px solid black;
  border-right: 7px solid black;
  z-index: -1;
}

.container {
  position: relative;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Loading DIV Test</title>
</head>
<body>
<div class="container">
<div class="mask"></div>
<div id="loadingBox" class="gradient-box">
<p>Loading.</p>
</div>
  </div>
</body>

,

我喜欢您使用 overflow: hidden 的原始想法,但要使其发挥作用,我必须包含一个额外的包装 div。

  • 外部包装器定义了一个填充,用作渐变边框的显示区域
  • 内部 div 只是带有黑色背景的内容框

.loading-box-container {
  --size: 200px;
  --radius: 10px;
  position: relative;
  width: var(--size);
  height: var(--size);
  padding: var(--radius);
  border-radius: var(--radius);
  overflow: hidden;
}

.loading-box {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: #000;
  border-radius: var(--radius);
}

.loading-box-container::before {
  content: '';
  width: 150%; /* The upscaling allows the box to fill its container even when rotated */
  height: 150%;
  position: absolute;
  top: -25%; left: -25%;
  background: conic-gradient(#0000ff00,#ff0000ff);
  animation: rotate-border 5s linear infinite;
}

@keyframes rotate-border {
    to {
        transform: rotate(360deg);
    }
}
<div class="loading-box-container">
  <div class="loading-box">
    <p>Loading</p>
  </div>
</div>

另一种选择:使用@property

​​>

使用 @property 有一个更优雅的解决方案,但不幸的是它只适用于 Chrome。我将其包括在内,以防有一天它变得更加普遍,或者对其他浏览器的支持对您的用例来说并不重要。

conic-gradient 函数有一个参数,允许您指定渐变开始的角度。如果我们可以只为那个参数设置动画,也许使用一个 CSS 变量,那么我们可以只用一个 div 设置边框动画,而无需实际旋转任何东西。

不幸的是,没有任何提示,浏览器不知道如何转换 CSS 变量。因此,我们使用 @property 来表示变量是一个角度,告诉浏览器如何转换它。

@property --rotation {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

.loading-box {
  --size: 200px;
  --radius: 10px;
  position: relative;
  width: var(--size);
  height: var(--size);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: #000;
  border-radius: var(--radius);
  margin: var(--radius);
}

.loading-box::before {
  --rotation: 0deg;
  content: '';
  width: calc(100% + 2 * var(--radius));
  height: calc(100% + 2 * var(--radius));
  border-radius: var(--radius);
  position: absolute;
  top: calc(-1 * var(--radius)); left: calc(-1 * var(--radius));
  background: conic-gradient(from var(--rotation),#0000ff00,#ff0000ff);
  animation: rotate-border 5s linear infinite;
  z-index: -1;
}

@keyframes rotate-border {
    to {
        --rotation: 360deg;
    }
}
<div class="loading-box">
  <p>Loading</p>
</div>

CanIUse for @property 表示从本文开始,这将仅适用于 Chrome 和 Edge