0

I've been trying to create a border animation that would look like in the attached image. So basically, the bright blue line will rotate around the box. The line should also be 3px whereas the actual border is 1px. I tried a few solutions I found on Codepen and tried to make them work for my case. But none of the CSS solutions worked.

I also tried a few other ideas, like having 4 different absolute positioned spans and each span has a before element that would animate according to the position of the previews element. But that was just a mess (and did not work either).

It seems something like this is not possible with pure CSS? I've been trying to get this done for almost 2 days now and none of the solutions were working as hoped. Anybody done something like that before? Would I need to make this an animated SVG in order to work? Any help is much appreciated.

enter image description here

Andreas
  • 412
  • 6
  • 19

1 Answers1

4

Since the border consists of exactly two separate line segments, ::before and ::after may be sufficient to do the trick!

This is overall a question of messing with @keyframes. The following example shows:

  • leftmost: only ::before, "head" element showing
  • middle: only ::after, "tail" element showing
  • rightmost: both pseudo-elements; this is the final result

body { background-color: #000000; }
.ex1, .ex2, .ex3 {
  display: inline-block;
  width: 150px; height: 150px;
  margin: 0 20px;
}

.ex1.snake-border::after { content: none; }
.ex2.snake-border::before { content: none; }

/* snake-border stuff: */
@keyframes snake-border-head {
  
  /*
  The snake's "head" stretches across a side of its container.
  The moment this head hits a corner, it instantly begins to
  stretch across the next side. (This is why some keyframe
  moments are repeated, to create these instantaneous jumps)
  */
  
  90% { left: 0; top: 0; width: 0; height: 40%; }
  90% { left: 0; top: 0; width: 0; height: 0; }
  100% { left: 0; top: 0; width: 40%; height: 0; } 0% { left: 0; top: 0; width: 40%; height: 0; }
  
  15% { left: 60%; top: 0; width: 40%; height: 0; }
  15% { left: 100%; top: 0; width: 0; height: 0; }
  25% { left: 100%; top: 0; width: 0; height: 40%; }
  
  40% { left: 100%; top: 60%; width: 0; height: 40%; }
  40% { left: 100%; top: 100%; width: 0; height: 0; }
  50% { left: 60%; top: 100%; width: 40%; height: 0; }
  
  65% { left: 0; top: 100%; width: 40%; height: 0; }
  65% { left: 0; top: 100%; width: 0; height: 0; }
  75% { left: 0; top: 60%; width: 0; height: 40%; }
  
}
@keyframes snake-border-tail {
  
  /*
  The "tail" of the snake is at full length when the head is at 0
  length, and vice versa. The tail always at a 90 degree angle
  from the head.
  */

  90% { top: 0%; height: 40%; }
  100% { left: 0; top: 0; width: 0; height: 0; } 0% { left: 0; top: 0; width: 0; height: 0; }
  
  15% { width: 40%; }
  25% { left: 100%; top: 0; width: 0; height: 0; }
  
  40% { height: 40%; }
  50% { left: 100%; top: 100%; width: 0; height: 0; }
  
  65% { left: 0%; width: 40%; }
  75% { left: 0; top: 100%; width: 0; height: 0; }
  
}

.snake-border {
  position: relative;
  box-shadow: inset 0 0 0 1px #00a0ff;
}
.snake-border::before, .snake-border::after {
  content: '';
  display: block;
  position: absolute;
  outline: 3px solid #00a0ff;
  animation-duration: 6s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}
.snake-border::before { animation-name: snake-border-head; }
.snake-border::after { animation-name: snake-border-tail; }
<div class="ex1 snake-border"></div>
<div class="ex2 snake-border"></div>
<div class="ex3 snake-border"></div>

I accomplished this using square containers, and the assumption that the snake's total length is 40% of the square's side-length. If you want to use rectangular containers, or an absolute-length snake travelling along a dynamically sized container, you'll have to fiddle with the values.

Gershom Maes
  • 7,358
  • 2
  • 35
  • 55