圆形按钮边框长度动画

5

body {
  font-family: sans-serif;
  background-color: black;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.button {
  position: relative;
  width: 200px;
  height: 40px;
  background-color: #083a65;
  border: none;
  color: white;
  font-size: 18px;
  border-radius: 10px;
}

.button::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  border-radius: 10px;
  border-top: 1px solid yellow;
  border-right: 1px solid yellow;
  animation: border-top-right-animation 2s infinite;
  
}

.button::after {
  content: "";
  position: absolute;
  right: 0px;
  bottom: 0px;
  width: 0;
  height: 0;
  border-radius: 10px;
  border-left: 1px solid yellow;
  border-bottom: 1px solid yellow;
  animation: border-bottom-left-animation 2s infinite;
}

@keyframes border-top-right-animation {
  0% {
    width: 0px;
    height: 0px;
  }
  25% {
    width: 100%;
    height: 0px;
  }
  50% {
    width: 100%;
    height: 100%;
  }
  100% {
    width: 100%;
    height: 100%;
  }
}

@keyframes border-bottom-left-animation {
  0% {
    width: 0px;
    height: 0px;
    opacity: 0;
  }
  50% {
    width: 0px;
    height: 0px;
    opacity: 0;
  }
  50.1% {
    width: 0px;
    height: 0px;
    opacity: 1;
  }
  75% {
    width: 100%;
    height: 0px;
    opacity: 1;
  }
  100% {
    width: 100%;
    height: 100%;
    opacity: 1;
  }
}
<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <div id="app"></div>
    <button class="button">My button</button>
  </body>
</html>

我有一个按钮边框动画,在按钮没有圆角时可以正常工作。如果按钮的border-radius为9px,我该如何实现相同的效果呢?我无法让动画在没有破坏右边框的情况下正确工作。

enter image description here


1
请将您的问题中涉及到的具体信息直接写在问题中,而不是仅仅提供一个外部平台的链接。 - undefined
希望有人能在这里提供帮助,因为我已经没有更多的主意了。 - undefined
关于这些伪元素上的border-radius的基本问题是,你只能在两个边界相遇的地方拥有一个圆角 - 但这只适用于::before的右上角和::after的左下角。 - undefined
在理论上,为其他边设置透明边框可以创建一个"淡出"的圆角边框 - 但是在这里你正在动画化这些伪元素的高度,所以在高度为0时仍然没有任何圆角,并且在0%到100%之间的高度,它会将更圆的角拉向按钮的一侧。我认为这将需要一种_完全_不同的方法。 - undefined
尝试过了,但是无法让它正常工作,我尝试了几个解决方案,但仍然无法做到正确。 - undefined
3个回答

6
所以我终于成功解决了。希望这能帮到别人。我为所有4行创建了4个不同的span,通过动画调整它们的宽度/高度,并将按钮的内容作为不同的元素绝对定位。
以下是代码:

body {
  margin: 0;
  padding: 0;
  height: 100vh;
  width: 100vw;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(0, 0, 0, 0.9);
}

.button {
  position: relative;
  width: 500px;
  height: 100px;
  background-color: #083a65;
  border: none;
  color: white;
  font-size: 18px;
  border-radius: 10px;
  overflow: hidden;
}

.button .text {
  position: absolute;
  width: calc(100% - 4px);
  height: calc(100% - 4px);
  top: 2px;
  left: 2px;
  background-color: #083a65;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
}

.button .top {
  position: absolute;
  left: 5px;
  top: 0px;
  width: 100%;
  height: 2px;
  background-color: yellow;
  animation: animate-top 1500ms linear;
}

.button .top::after {
  content: "";
  position: absolute;
  top: 0;
  right: 5px;
  width: 10px;
  height: 10px;
  background-color: yellow;
}

.button .right {
  position: absolute;
  right: 0;
  top: -5px;
  width: 2px;
  height: 100%;
  background-color: yellow;
  animation: animate-right 1500ms linear;
}

.button .right::before {
  content: "";
  position: absolute;
  bottom: -5px;
  right: 0;
  width: 10px;
  height: 10px;
  background-color: yellow;
}

.button .bottom {
  position: absolute;
  right: 0;
  bottom: 0px;
  width: 100%;
  height: 2px;
  background-color: yellow;
  animation: animate-bottom 1500ms linear;
}

.button .bottom::before {
  content: "";
  position: absolute;
  bottom: 0;
  left: 0;
  width: 10px;
  height: 10px;
  background-color: yellow;
}

.button .left {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 2px;
  height: 100%;
  background-color: yellow;
  animation: animate-left 1500ms linear;
}

.button .left::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 10px;
  height: 10px;
  background-color: yellow;
}

@keyframes animate-top {
  0% {
    width: 0px;
  }
  25% {
    width: 100%;
  }
  50% {
    width: 100%;
  }
  75% {
    width: 100%;
  }
  100% {
    width: 100%;
  }
}

@keyframes animate-right {
  0% {
    height: 0;
  }
  25% {
    height: 0;
  }
  50% {
    height: 100%;
  }
  75% {
    height: 100%;
  }
  100% {
    height: 100%;
  }
}

@keyframes animate-bottom {
  0% {
    width: 0;
  }
  25% {
    width: 0;
  }
  50% {
    width: 0;
  }
  75% {
    width: 100%;
  }
  100% {
    width: 100%;
  }
}

@keyframes animate-left {
  0% {
    height: 0;
  }
  25% {
    height: 0;
  }
  50% {
    height: 0;
  }
  75% {
    height: 0;
  }
  100% {
    height: 100%;
  }
}
 <button class="button">
   <span class="top"></span>
   <span class="right"></span>
   <span class="bottom"></span>
   <span class="left"></span>
   <span class="text">Animated button</span>
 </button>


如果你增加动画时间,你会发现它是不均匀的。另外,你正在对宽度和高度进行动画处理,这并不是很有效率。 - undefined
请提供更好的代码答案。 - undefined
我已经给你提供了以下的一种实施方法。 - undefined

4
通常,stroke-dasharraystroke-dashoffset属性用于svg形状的动画效果。 类似于这样的效果:

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


body {
  font-family: sans-serif;
  background-color: black;
  height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.button {
  position: relative;
  width: 200px;
  height: 40px;
  background-color: #083a65;
  border: 0;
  color: white;
  font-size: 18px;
  border-radius: 10px;
  cursor: pointer;
  max-width: 100%;
}

button svg {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

button rect {
  animation: button-border 2s linear both;
}

@keyframes button-border {
  to {
    stroke-dashoffset: 0;
  }
}
<button
  type="button"
  class="button"
>
  My button
  <svg
    viewBox="0 0 200 40"
    fill="none"
    preserveAspectRatio="none"
  >
    <rect
      vector-effect="non-scaling-stroke"
      x="0.5"
      y="0.5"
      width="199"
      height="39"
      rx="9.5"
      stroke="yellow"
      stroke-dasharray="460"
      stroke-dashoffset="460"
    />
  </svg>
</button>


这似乎是一个不错的解决方案,但为什么当移除infinite属性时,它会执行两次动画?而且当动画完成一圈后,它能保留这个黄色边框吗? - undefined
我明白你的意思了,已经更新了答案。那只是一个例子而已。 - undefined
这个方法很有效,我认为这是一个更好的解决方案。谢谢你的帮助! - undefined
1
我很高兴能够帮助! - undefined
这应该被添加到几乎所有的CSS框架中……谈论一些人们想要重新创建的东西,但对于增加价值来说又难以实现(在大多数情况下,需要每个项目中的个人编写)- 很好的解决方案。 - undefined

-2
你可以使用conic-gradient和外部框。

<!DOCTYPE html>
<html>
  <head>
    <title>Call to Action Border Animation</title>
    <style>
      body {
        font-family: sans-serif;
        background-color: black;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      
      .outer-box {
        --border-angle: 0deg;
        max-width: max-content;
        background: conic-gradient(
          from 280deg,
          yellow var(--border-angle),
          transparent var(--border-angle)
        );
        border-radius: 10px;
        -webkit-animation: bg-spin 3s linear infinite;
        animation: bg-spin 3s linear infinite;
      }

      .outer-box:hover {
        -webkit-animation-play-state: paused;
        animation-play-state: paused;
      }
      
      @-webkit-keyframes bg-spin {
        to {
          --border-angle: 360deg;
        }
      }
      @keyframes bg-spin {
        to {
          --border-angle: 360deg;
        }
      }

      .button {
        margin: 0;        
        width: 200px;
        height: 40px;
        background-color: #083a65;
        border: none;
        color: white;
        font-size: 18px;
        border-radius: inherit;
      }
      
      .inner-box {
        border-radius: calc(10px - 2px);
        border: 2px solid transparent;
      }

      @property --border-angle {
        syntax: "<angle>";
        inherits: true;
        initial-value: 0deg;
      }
      
    </style>
  </head>
  <body>
    <div class="outer-box">
      <div class="inner-box">
        <button class="button">My Button</button>
      </div>
    </div>  
  </body>
</html>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接