0

Im trying to animate a button on my webpage which is a basically a timed animation that starts off at the top of the button and then eventually fills up the entire border of the button. I've attached an image as its hard to describe what I mean.

Blue animation

I'm sure that this can be done with Keyframes but I have no idea how. I've tried something like this to start:

  @keyframes borderblueanim {
    0% {border-color: #fff; }
    100% {border-color: blue; }
  }
  @-webkit-keyframes borderblueanim {
    0% {border-color: #fff; }
    100% {border-color: blue; }
  }

  animation: borderblueanim 5s infinite;
   -webkit-animation: borderblueanim 2s infinite;

But its not correct. Would appreciate any ideas and help.

Jason Chu
  • 355
  • 1
  • 2
  • 14
  • Hmm. So you want the border to fill up in a circle e.g. like a spinner or do you want to fade in the new color of the whole border? please check these samples and tell me if this is what your looking for? https://codepen.io/Nasir_T/pen/VzxvWR – Nasir T Aug 21 '17 at 20:43
  • The first button in your codepen is more what Im looking for! It just has to be gradual instead of 1 section showing up at a time. So basically, like the hands of a clock as the hour goes by. – Jason Chu Aug 21 '17 at 20:59
  • Actually issue is the border does not have a percentage coloring. It only has four sides so can only manipulate that using css keyframes. I have to go now. I will look into a solution for you if you dont find what your looking for till tomorrow. Hope someone helps you out in my absense. – Nasir T Aug 21 '17 at 21:08
  • Check out Tyler Bramer's Answer. It uses svg which makes it possible instead of using borders on div element. I think that should satisfy your need. – Nasir T Aug 21 '17 at 21:10
  • May be this https://stackoverflow.com/a/28866340/1926369 can help you – vals Aug 21 '17 at 21:15

2 Answers2

3

One way you can do this is to animate the stroke-offset of a path. I've included sample code using a circle path. Depending on how big your element is you will need to change your dasharray and dashoffset values.

svg {
  fill: #eee;
  overflow: visible;
  transform-origin:50% 50%;
  transform: rotate(-90deg);
}
.path {
  stroke: blue;
  stroke-width: 4;
  stroke-dasharray: 800;
  stroke-dashoffset: 800;
  animation: borderblueanim 2s infinite;
  
}

@keyframes borderblueanim {
  from {
    stroke-dashoffset: 800;
  }
  to {
    stroke-dashoffset: 0;
  }
}
<svg width="200" height="200" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<circle class="path" cx="100" cy="100" r="100"/>
</svg>
Tyler Bramer
  • 275
  • 2
  • 14
  • Hey Tyler, thanks for your response! Unfortunately I can't test it on my dev environment because we recently ran into SSH config problems. Once its resolved, I'll try to implement your solution. – Jason Chu Aug 24 '17 at 19:11
0

Something like this might work. This uses SCSS

//Colors
$background: #fefefe;
$text: #4b507a;

$cyan: #60daaa;
$yellow: #fbca67;
$orange: #ff8a30;
$red: #f45e61;
$purple: #6477b9;
$blue: #0eb7da;

// Basic styles
button {
  background: none;
  border: 0;
  box-sizing: border-box;
  margin: 1em;
  padding: 1em 2em;
  
  // Using inset box-shadow instead of border for sizing simplicity
  box-shadow: inset 0 0 0 2px $red;
  color: $red;
  font-size: inherit;
  font-weight: 700;

  // Required, since we're setting absolute on pseudo-elements
  position: relative;
  vertical-align: middle;

  &::before,
  &::after {
    box-sizing: inherit;
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
  }
}



// Border spins around element
// ::before holds three borders that appear separately, one at a time
// ::after holds one border that spins around to cover ::before's borders, making their appearance seem smooth

.spin {
  width: 5em;
  height: 5em;
  padding: 0;
  
  &:hover {
    color: $blue;
  }

  &::before,
  &::after {
    top: 0;
    left: 0;
  }

  &::before {
    border: 2px solid transparent; // We're animating border-color again
  }

  &:hover::before {
    border-top-color: $blue; // Show borders
    border-right-color: $blue;
    border-bottom-color: $blue;

    transition:
      border-top-color 0.15s linear, // Stagger border appearances
      border-right-color 0.15s linear 0.10s,
      border-bottom-color 0.15s linear 0.20s;
  }

  &::after {
    border: 0 solid transparent; // Makes border thinner at the edges? I forgot what I was doing
  }

  &:hover::after {
    border-top: 2px solid $blue; // Shows border
    border-left-width: 2px; // Solid edges, invisible borders
    border-right-width: 2px; // Solid edges, invisible borders
    transform: rotate(270deg); // Rotate around circle
    transition:
      transform 0.4s linear 0s,
      border-left-width 0s linear 0.35s; // Solid edge post-rotation
  }
}

.circle {
  border-radius: 100%;
  box-shadow: none;
    
  &::before,
  &::after {
    border-radius: 100%;
  }
}

html {
  background: $background;
}

body {
  background: $background;
  color: $text;
  font: 300 24px/1.5 Lato, sans-serif;
  margin: 1em auto;
  max-width: 36em;
  padding: 1em 1em 2em;
  text-align: center;
}

.buttons {
  isolation: isolate;
}

h1 {
  font-weight: 300;
  font-size: 2.5em;
}
  <button class="spin circle">Spin Circle</button>
Nicholas
  • 3,529
  • 2
  • 23
  • 31
  • Hmm its more that on initial page load, the button animation should start empty and then gradually fill up the inset color of the button. – Jason Chu Aug 21 '17 at 20:31