【问题标题】:CSS animated gradient border on a DIVDIV上的CSS动画渐变边框
【发布时间】:2021-09-30 13:29:39
【问题描述】:

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

根据https://css-tricks.com/gradient-borders-in-css/ 上的一个例子,我已经很接近了

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

但是,一旦添加了动画,因为整个 :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>

我尝试过使用 overflow: hidden;但是边框就消失了.. 有没有办法“屏蔽” :before 元素,使这个加载 Div 后面的任何东西在它后面仍然可见,从而使边框保持其预期的宽度?

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

【问题讨论】:

    标签: html css css-animations css-gradients


    【解决方案1】:

    您好,这是您要找的吗?

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

    然后,我将蒙版的大小设置为比您的可见区域大一点,使其成为透明背景,然后给它一个与您的背景颜色相同的大轮廓,以有效地掩盖边框。然后我摆弄了掩码、加载框和之前的 z-indexs。我还在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>

    【讨论】:

    • 谢谢约翰,我确实想知道是否需要包装 DIV。我会接受这个答案(因为它是第一个),但由于有关使用 \@property 的附加信息,我觉得我不得不接受@Auroratide 的回答。
    【解决方案2】:

    我喜欢你最初使用 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

    【讨论】:

    • 不错! @property 方法很有趣,但我现在需要跨浏览器兼容性,所以它是额外的 DIV - 它看起来很棒。 (我还使用border-radius: 50%; 创建了一个 roudn 版本,它避免了问题而不是解决它。现在我需要决定哪个看起来最适合页面设计的其余部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多