Search code examples
cssanimationcss-transitionssmoothingkeyframe

How would I make the transition smoother when hovering over button #2


How would I make the transition of the black border smoother when hovering over button #2?

Currently, there is a slight delay when hovering over button #2. Is there a better way to do it?

I am looking to make the circular button's border to quickly fill out. Currently, it lags a bit too much which I find to be distracting.

Thank you!

.btn {
  width: 130px;
  height: 50px;
  border: none;
  margin: 4rem;
}

.btn2 {
    position: relative;
    overflow: hidden;
    transition:  height .5s;
}


.btn2::after {
  content:"";
  display: block;
  background-color: black;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  position: absolute;
  top:50px;
  left:50px;
  opacity: .2;
  transition: top 1.2s ease-out;
}

.btn2::before {
  content:"";
  display: block;
  background-color: black;
  width: 25px;
  height: 25px;
  border-radius: 50%;
  position: absolute;
  top:-50px;
  left:15px;
  opacity: .2;
  transition: top 1.2s ease-out;
}


.btn2:hover::before{
  position: absolute;
  top:34px
}

.btn2:hover::after{
  position: absolute;
  top:70px
}

.btn2:hover {
  height: 130px;
  border-radius: 50%;
  animation:circle 4s ease;
}

@keyframes circle {
  0%{ border:none}
  10%{border-top:2px solid}
  25%{border-right:2px solid}
  45%{border-bottom:2px solid}
  65%{border-left:2px solid}
  85%{border:2px solid}
  100%{border:2px solid}
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>A Great Demo on CodePen</title>
</head>
<body>
  <div class="wrap">
    
   <button class="btn btn2">button 2 !!</button>
  </div>
  
</body>
</html>


Solution

  • The problem arises because the length of a border is not animatable. Therefore when in an animation you change, say, the top border to be solid/with color/with width all that top border is shown at once. So, in the given animation there is jerkiness at each animation point as a border is drawn. Coupled with this is them not being straight borders which gives a sort of tapered look to the ends of each border.

    Transform rotate is animatable and should be smooth so laying another circle on top of the button and rotating it to reveal the borders bit by bit as they are drawn should work. However, I have run across some problems as on a high def screen with radius 50% the matching of pixels (screen pixels) is not exact (in terms of CSS pixels) - little bits of a border can be seen even if ostensibly covered by the circle on top.

    So, this is not a perfect answer to the question but may give some ideas of how to get the desired affect.

    It puts another 'button' on top of btn2 and has them both within a container. btn2 is animated to reveal the 4 borders in turn (much as in the code given in the question) and the new button on top 'reveal's these borders as it rotates. This extra button could possibly be a pseudo element associated with the container, and if wrap is not being used for other things that could become the container without the need for changing the HTML.

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>Draw circle</title>
    <style>
    * {
      margin: 0;
      padding: 0;  
    }
    
        .btn2container {
          position: relative;
        }
        .btn {
          width: 130px;
          height: 50px;
          border: none;
          margin: 4rem;
          --bg: #eeeeee;
        }
    
        .btn2 {
            position: relative;
            overflow: hidden;
            transition:  height .5s;
            border-width: 3px;
            background-color: var(--bg);
        }
    
    
        .btn2container:hover .btn2 {
          border-style: none;
          border-color: transparent;
          height: 130px;
          border-radius: 50%;
          animation:circle 4s linear;
          animation-fill-mode: forwards;
          border-width: 3px;
        }
        .btn2container .revealer {
          position: absolute;
          animation-name: none;
          animation-duration: 4s;
          animation-fill-mode: forwards;
          animation-iteration-count: 1;
          animation-timing-function: linear;
          z-index:999;
          transform: rotate(0deg);
          width: 130px;
          height: 130px;
          border-radius: 50%;
          border-style: solid;
          display: none;
          overflow: hidden;
          background-color:transparent;
          border-style: solid;
          border-width:3px;
          border-color: red transparent transparent transparent;
        }
        .btn2container:hover .revealer {
          animation-name: reveal;
          display: block;
        }
      @keyframes reveal {
        0% {
          display: block;
          opacity: 1;
          height: 130px;
          width:130px;
          transform: rotate(0deg);
          border-width:3px;
          border-color: var(--bg) transparent transparent transparent;
          box-shadow: 0 0 0 2pt white;
        }
        74.9999% {
          transform: rotate(270deg);
          border-width:3px;
          border-color: var(--bg) transparent transparent transparent;
          box-shadow: 0 0 0 2pt white;
        }
        75% {
          border-width: 2px;
          border-color: transparent transparent transparent black;
        }
        99.9% {
          transform: rotate(360deg);
          border-color: transparent transparent transparent black;
          opacity: 1;
          border-width: 2px;
        }
        100% {
          opacity:0;
          border-width: 3px;
        }
      }
        @keyframes circle {
          0% {
            border-style: solid;
            border-color: black transparent transparent transparent;
            border-width: 2px;
          }
          24.99% {
            border-color: black transparent transparent transparent;
            border-width: 3px;
          }
          25% {
            border-color: black  black transparent transparent;
            border-width: 3px;
          }
          49.99% {
            border-color: black  black transparent transparent;
            border-width: 3px;
          }
          50% {
            border-color: black black black transparent;
            border-width: 3px;
          }
          99.99% {
            border-color: black black black transparent;
            border-width: 3px;
          }
          100% {
            border-color: black;
            border-style: solid;
            border-width: 3px;
          }
          }
    
        .btn2::after {
          content:"";
          display: block;
          background-color: black;
          width: 40px;
          height: 40px;
          border-radius: 50%;
          position: absolute;
          top:50px;
          left:50px;
          opacity: .2;
          transition: top 1.2s ease-out;
        }
    
        .btn2::before {
          content:"";
          display: block;
          background-color: black;
          width: 25px;
          height: 25px;
          border-radius: 50%;
          position: absolute;
          top:-50px;
          left:15px;
          opacity: .2;
          transition: top 1.2s ease-out;
        }
    
    
        .btn2container:hover .btn2::before{
          position: absolute;
          top:34px
        }
    
        .btn2container:hover .btn2::after{
          position: absolute;
          top:70px
        }
    
        </style>
        </head>
    <body>
        <div class="wrap">       
        <div class="btn2container">
         <button class="btn revealer"></button>
         <button class="btn btn2">button 2 !!</button>
       </div>
       </div>     
     </body>
    </html>