Jason Chu
Jason Chu

Reputation: 385

Animate CSS Button border with Keyframes

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.

Upvotes: 0

Views: 2990

Answers (2)

Tyler Bramer
Tyler Bramer

Reputation: 275

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>

Upvotes: 3

Nicholas
Nicholas

Reputation: 3784

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>

Upvotes: 0

Related Questions