Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a moving border animation work on a square element

I am trying to get a moving border CSS animation to work on a square but I can't quite work out how to get it to work. It works fine on a circle as I just use the rotate transition with the key frames. This is my current markup.

.box {
  width: 50px;
  height: 50px;
  margin: 50px auto;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 50%;
  position: relative;
  -webkit-transition: all 1s ease;
  transition: all 1s ease;
}
.box .border {
  position: absolute;
  top: -4px;
  left: -4px;
  width: 50px;
  height: 50px;
  background: transparent;
  border: 4px solid transparent;
  border-top-color: orangered;
  border-radius: 50%;
  animation-name: border;
  -webkit-animation-duration: 2s;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-timing-function: linear;
}
@-webkit-keyframes border {
  from {
    -webkit-transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(360deg);
  }
<div class="box">
  <div class="border"></div>
</div>
like image 756
rufus Avatar asked Jan 09 '17 12:01

rufus


People also ask

Can you animate borders in CSS?

CSS border animation is useful for giving a border image or container element a unique style. To make a website's user interface (UI) more attractive, use a CSS border animation design. CSS border animation is useful for giving a border image or container element a unique style.

Are borders Animatable?

As repeatable list of simple list of length, percentage, or calc. As each of the properties for border width and border color. Border style is not animatable.


1 Answers

The animation in question is using a rotate transform with a stationary border to create the illusion of a moving border whereas it actually is not. With a square, you cannot use a similar model as when we rotate a square it doesn't stay the same like a circle does.

So the available options would be to make use of a SVG stroke-dashoffset based animation like in the below snippet. The stroke-dasharray property provides the length/width of the stroke (1st param) and the length/width of the space (2nd param). The stroke-dashoffset property specifies the offset from the start position at which the stroke should be painted.

polygon {
  stroke: red;
  stroke-width: 3;
  stroke-dasharray: 50, 750;
  stroke-dashoffset: 0;
  fill: none;
  animation: border 5s linear infinite;
}
@keyframes border {
  to {
    stroke-dashoffset: -800;
  }
}
<svg width="210" height="210">
  <polygon points="5,5 205,5 205,205 5,205" />
</svg>

If you want a pure CSS solution then you could make use of a linear-gradient based solution like in the below snippet. Here we create four strips of background images based on linear gradients which are of the same thickness of the border. These strips have the color for the required width and is then transparent for the rest. By animating the background-position , we can get something that is close to the effect that we are looking for.

Note that background-position animation works only with fixed pixel values and so the dimensions of the box need be known prior. Everytime the value changes, the background-position values need to be re-configured accordingly.

div {
  height: 200px;
  width: 200px;
  box-sizing: border-box;
  background-image: linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px), linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px);
  background-size: 100% 3px, 3px 100%, 100% 3px, 3px 100%; /* one of the values is the border thickness, other is 100% */
  background-repeat: no-repeat;
  background-position: -50px 0px, right -50px, 200px bottom, 0px 200px; /* positions such that none of the images are visible at start */
  animation: border 5s linear; /* add infinite if you need infinite animation */
}
@keyframes border {
  /* animate position such that they come into view and go out of it one by one */
  25% {
    background-position: 200px 0px, right -50px, 200px bottom, 0px 200px;
  }
  50% {
    background-position: 200px 0px, right 200px, 200px bottom, 0px 200px;
  }
  75% {
    background-position: 200px 0px, right 200px, -50px bottom, 0px 200px;
  }
  100% {
    background-position: 200px 0px, right 200px, -50px bottom, 0px -50px;
  }
}
<div class='border-animation'></div>

If you want a pure CSS solution more closer to the SVG one then we can add more keyframes to the animation like the below snippet.

div {
  height: 200px;
  width: 200px;
  box-sizing: border-box;
  background-image: linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px), linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px);
  background-size: 100% 3px, 3px 100%, 100% 3px, 3px 100%;
  background-repeat: no-repeat;
  background-position: -50px 0px, right -50px, 200px bottom, 0px 200px;
  animation: border 5s linear;
}
@keyframes border {
  20% {
    background-position: 150px 0px, right -50px, 200px bottom, 0px 200px;
  }
  25% {
    background-position: 200px 0px, right 0px, 200px bottom, 0px 200px;
  }
  45% {
    background-position: 200px 0px, right 150px, 200px bottom, 0px 200px;
  }
  50% {
    background-position: 200px 0px, right 200px, 150px bottom, 0px 200px;
  }
  70% {
    background-position: 200px 0px, right 200px, 0px bottom, 0px 200px;
  }
  75% {
    background-position: 200px 0px, right 200px, -50px bottom, 0px 150px;
  }
  95% {
    background-position: 200px 0px, right 200px, -50px bottom, 0px 0px;
  }
  100% {
    background-position: 200px 0px, right 200px, -50px bottom, 0px -50px;
  }
}
<div class='border-animation'></div>

Here is an even more complete looking infinite animation using pure CSS:

div {
  height: 200px;
  width: 200px;
  box-sizing: border-box;
  background-image: linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px), linear-gradient(to right, red 50px, transparent 50px), linear-gradient(to bottom, red 50px, transparent 50px);
  background-size: 100% 3px, 3px 100%, 100% 3px, 3px 100%;
  background-repeat: no-repeat;
  background-position: 0px 0px, right -50px, 200px bottom, 0px 200px;
  animation: border 5s linear infinite;
}
@keyframes border {
  20% {
    background-position: 150px 0px, right -50px, 200px bottom, 0px 200px;
  }
  25% {
    background-position: 200px 0px, right 0px, 200px bottom, 0px 200px;
  }
  45% {
    background-position: 200px 0px, right 150px, 200px bottom, 0px 200px;
  }
  50% {
    background-position: 200px 0px, right 200px, 150px bottom, 0px 200px;
  }
  70% {
    background-position: 200px 0px, right 200px, 0px bottom, 0px 200px;
  }
  75% {
    background-position: 200px 0px, right 200px, -50px bottom, 0px 150px;
  }
  95% {
    background-position: 200px 0px, right 200px, -50px bottom, 0px 0px;
  }
  95.1% {
    background-position: -50px 0px, right 200px, -50px bottom, 0px 0px;
  }
  100% {
    background-position: 0px 0px, right 200px, -50px bottom, 0px -50px;
  }
}
<div class='border-animation'></div>
like image 151
Harry Avatar answered Oct 02 '22 14:10

Harry