CSS过渡期间绘制边框颜色

6

button {
  background: none;
  border: 0;
  box-sizing: border-box;
  margin: 1em;
  padding: 1em 2em;
  box-shadow: inset 0 0 0 2px #f45e61;
  color: #f45e61;
  font-size: inherit;
  font-weight: 700;
  position: relative;
  vertical-align: middle;
}
button::before, button::after {
  box-sizing: inherit;
  content: " ";
  position: absolute;
  width: 100%;
  height: 100%;
}
.draw {
  transition: color 0.25s;
}
.draw::before, .draw::after {
  border: 2px solid transparent;
  width: 0;
  height: 0;
  transition: width 1.25s ease-out 1.25s, height 1.25s ease-out 1.25s;

}
.draw::before {
  top: 0;
  left: 0;
}
.draw::after {
  bottom: 0;
  right: 0;
}
.draw:hover {
  color: #60daaa;
}
.draw:hover::before, .draw:hover::after {
  width: 100%;
  height: 100%;
}
.draw:hover::before {
  border-top-color: #60daaa;
  border-right-color: #60daaa;
  transition: width 0.25s ease-out, height 0.25s ease-out 0.25s;
}
.draw:hover::after {
  border-bottom-color: #60daaa;
  border-left-color: #60daaa;
  transition: border-color 0s ease-out 0.5s, width 0.25s ease-out 0.5s, height 0.25s ease-out 0.75s;
}
<section class="buttons">
  <button class="draw">Draw</button>
</section>

我有一个工作的笔(https://codepen.io/anon/pen/vdgdxO),可以在悬停时(上、右、下、左)更改元素的边框颜色,并进行平滑的过渡。
我想能够在几秒钟后“反转”边框颜色更改。基本上,当相反的边框颜色更改时,我希望更改边框颜色:
- 上边框更改颜色 - 右侧边框更改颜色 - 底部边框更改颜色和上部边框返回其原始颜色 - 左边框更改颜色和右边框返回其原始颜色 - 上边框更改颜色和底部边框返回其原始颜色 - 右边框更改颜色和左边框返回其原始颜色,等等
现在我只能更改颜色,但不知道如何“反转”它。我还希望这个过渡无限循环,但我不知道从哪里开始。有什么建议吗?

无限循环,当悬停时执行? - Gerardo BLANCO
看起来更适合使用动画而不是过渡效果!CSS动画可以像Gerardo建议的那样循环播放。 - Frish
1个回答

14

我会使用多个linear-gradient和一个复杂的动画(通过动画化每个渐变的大小/位置)来获得最终结果。如果你掌握了技巧,你可以轻松调整不同的值来获得任何你想要的动画。

.draw {
  padding: 20px 50px;
  outline:none;
  border: none;
  box-shadow: none;
  background-image: 
  linear-gradient(#f45e61, #f45e61), 
  linear-gradient(#f45e61, #f45e61), 
  linear-gradient(#f45e61, #f45e61), 
  linear-gradient(#f45e61, #f45e61), 
  
  linear-gradient(#60daaa, #60daaa), 
  linear-gradient(#60daaa, #60daaa), 
  linear-gradient(#60daaa, #60daaa), 
  linear-gradient(#60daaa, #60daaa);
  
  background-position: 0 0, 0 0, 0 100%, 0 100%, 
                       0 0, 0 0, 0 100%, 100% 0;
  background-size: 3px 0%, 0% 3px, 0% 3px, 3px 0%,  
                   3px 100%, 100% 3px, 100% 3px,3px 100%;
  background-color:transparent;
  background-repeat:no-repeat;
  transition:0.2s linear;
}

.draw:hover {
  background-position: 0 100%, 0 0, 0 100%, 100% 0, 
                       0 0, 0 0, 0 100%, 100% 0;
  background-size: 3px 0%, 100% 3px, 0% 3px,3px 0%,  
                   3px 100%, 100% 3px, 100% 3px,3px 100%;
  animation: animate 1.4s linear infinite 0.2s;
}

@keyframes animate {
  0% {
  background-position: 0 100%, 0 0, 0 100%, 100% 0, 
                       0 0, 0 0, 0 100%, 100% 0;
  background-size: 3px 0%, 100% 3px, 0% 3px,3px 0%,  
                   3px 100%, 100% 3px, 100% 3px,3px 100%;
  }
  40% {
  background-position: 0 100%, 100% 0, 100% 100%, 100% 0, 
                       0 0, 0 0, 0 100%, 100% 0;
  background-size: 3px 0%, 100% 3px, 0% 3px,3px 100%,  
                   3px 100%, 100% 3px, 100% 3px,3px 100%;
  }
  60% {
  background-position: 0 100%, 100% 0, 100% 100%, 100% 100%, 
                       0 0, 0 0, 0 100%, 100% 0;
  background-size: 3px 0%, 0% 3px, 100% 3px,3px 100%,  
                   3px 100%, 100% 3px, 100% 3px,3px 100%;
  }
  70% {
  background-position: 0 100%, 100% 0, 0% 100%, 100% 100%, 
                       0 0, 0 0, 0 100%, 100% 0;
  background-size: 3px 100%, 0% 3px, 100% 3px,3px 0%,  
                   3px 100%, 100% 3px, 100% 3px,3px 100%;
  }
  80% {
  background-position: 0% 0%, 0% 0, 0% 100%, 100% 100%, 
                       0 0, 0 0, 0 100%, 100% 0;
  background-size: 3px 100%, 0% 3px, 0% 3px,3px 0%,  
                   3px 100%, 100% 3px, 100% 3px,3px 100%;
  }
  100% {
  background-position: 0% 0%, 0 0, 0 100%, 100% 100%, 
                       0 0, 0 0, 0 100%, 100% 0;
  background-size: 3px 0%, 100% 3px, 0% 3px,3px 0%,  
                   3px 100%, 100% 3px, 100% 3px,3px 100%;  
  }
}
<button class="draw">Draw</button>

它是如何工作的?

结构: 我们有8个 linear-gradient。其中4个将简单创建初始边框并且不会移动(它们位于底部层),另外4个将用于绘制线条,这些线条将在初始边框上方创建我们的动画(它们位于顶部层)。

顺序很重要,因为在背景属性中,我们将每个渐变色都有8个值。您将注意到3px 的值将仅指定每个渐变色的宽度或高度(类似于 border-width),并且在动画期间不会更改。

动画: 我将调整每个渐变色的位置/大小来创建动画。它分为两个部分:小的过渡和大的动画。过渡只是用于创建动画的初始状态,因此过渡所使用的持续时间与动画的延迟相同。

  1. 第一步是将顶部边框从左到右动画化。为此,渐变应该位于(0,0)[ top,left ],大小为0% 3px [ width height ]。然后我只需将大小更改为100% 3px,就可以获得所需的动画效果(如上述,3px不会更改)。

    enter image description here

  2. 现在,要动画化第二个边框,我们做同样的事情。 我们需要一个渐变色,其位置位于(100%,0)[ top,right ],大小为3px 0% [ width height ],我们将其动画化为3px 100%

enter image description here

  1. To animate the third border and hide the first one, we need to adjust the position of the gradient to make it (100%,0) [top,right] instead of (0,0), and then set its size back to 0% 3px. This will create a left to right animation. We continue this logic until we get back to the initial state and use infinite in the animation property for the needed effect.

enter image description here

  1. The main idea is to have a gradient with the size equal to 0% that animates to full size (100%) in a given direction, then change its position, and finally animate back its size to 0. This is mixed with the other three gradients for the animation.

In an updated version, a pseudo-element is used for the static border, reducing the number of gradients used in the animation to four.

.draw {
  position:relative;
  padding: 20px 50px;
  outline:none;
  border: none;
  box-shadow: none;
  background-image: 
  linear-gradient(#f45e61, #f45e61), 
  linear-gradient(#f45e61, #f45e61), 
  linear-gradient(#f45e61, #f45e61), 
  linear-gradient(#f45e61, #f45e61);
  
  background-position: 0 0, 0 0, 0 100%, 0 100%;
  background-size: 3px 0%, 0% 3px, 0% 3px, 3px 0%;
  background-color:transparent;
  background-repeat:no-repeat;
  transition:0.2s linear;
}
.draw:before {
  content:"";
  position:absolute;
  z-index:-1;
  top:0;
  right:0;
  left:0;
  bottom:0;
  border:3px solid #60daaa;
}

.draw:hover {
  background-position: 0 100%, 0 0, 0 100%, 100% 0;
  background-size: 3px 0%, 100% 3px, 0% 3px,3px 0%;
  animation: animate 1.4s linear infinite 0.2s;
}

@keyframes animate {
  0% {
  background-position: 0 100%, 0 0, 0 100%, 100% 0;
  background-size: 3px 0%, 100% 3px, 0% 3px,3px 0%;
  }
  40% {
  background-position: 0 100%, 100% 0, 100% 100%, 100% 0;
  background-size: 3px 0%, 100% 3px, 0% 3px,3px 100%;
  }
  60% {
  background-position: 0 100%, 100% 0, 100% 100%, 100% 100%;
  background-size: 3px 0%, 0% 3px, 100% 3px,3px 100%
  }
  70% {
  background-position: 0 100%, 100% 0, 0% 100%, 100% 100%;
  background-size: 3px 100%, 0% 3px, 100% 3px,3px 0%;
  }
  80% {
  background-position: 0% 0%, 0% 0, 0% 100%, 100% 100%;
  background-size: 3px 100%, 0% 3px, 0% 3px,3px 0%;
  }
  100% {
  background-position: 0% 0%, 0 0, 0 100%, 100% 100%;
  background-size: 3px 0%, 100% 3px, 0% 3px,3px 0%  
  }
}
<button class="draw">Draw</button>


@JorelAmthor 嗯,这是一个小缺点 :) 因为当动画结束时,它们全部消失了,所以不容易始终显示边框,因为在开始时没有边框...但我正在尝试想出一个诀窍:) ...顺便说一下,这些值看起来很困难,但只需想象您有8个渐变,并且对于每个渐变,您都有一个大小和位置,在同一属性中定义,因此删除动画并播放值以了解它们的工作原理 :) - Temani Afif
@JorelAmthor 好的,我会尝试添加更多解释;)我知道有点棘手:)...给我几分钟;) - Temani Afif
@JorelAmthor也加入了解释 ;) - Temani Afif
1
太棒了!我希望我能给这个点赞更多!非常感谢。 - Jorel Amthor
1
@JorelAmthor 欢迎 :) 我还添加了另一个更新,其中使用了较少的渐变,以使其更容易处理 ;) 因为我知道处理许多背景可能会很棘手。 - Temani Afif
显示剩余3条评论

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