A CSS only solution where I will animate only opacity and tranformation. Should use less ressources. Not as perfect as the SVG one but good enough as an alternative:
.outer {
border-radius: 5px;
position: relative;
width: 300px;
height: 300px;
border: 1px solid gray;
margin:15px;
clip-path:inset(-5px);
}
.outer::before,
.outer::after,
.outer span::before,
.outer span::after {
content:"";
position: absolute;
opacity:0;
transition:1s;
animation: 1s linear infinite;
}
.outer::before,
.outer::after {
height: 2px;
left: -5px;
width: calc(100% + 20px);
background: repeating-linear-gradient(to right, red 0 5px, transparent 0 10px);
animation-name:drawX;
}
.outer span::before,
.outer span::after {
width: 2px;
top: -5px;
height: calc(100% + 20px);
background: repeating-linear-gradient(to bottom, red 0 5px, transparent 0 10px);
animation-name:drawY;
}
.outer::before {top: -5px; animation-direction:reverse;}
.outer span::before {right: -5px; animation-direction:reverse;}
.outer::after { bottom: -5px;}
.outer span::after { left: -5px;}
.outer:hover::before,
.outer:hover::after,
.outer:hover span::before,
.outer:hover span::after {
opacity:1;
}
@keyframes drawX {
to {
transform: translateX(-10px);
}
}
@keyframes drawY {
to {
transform: translateY(-10px);
}
}
<div class="outer">
<span></span>
</div>
With Some CSS variables to control everything:
.outer {
--th:2px; /* border thickness */
--w:5px; /* width of the color*/
--s:5px; /* the space between color*/
--o:5px; /* the offset */
--c:red;
--g: var(--c) 0 var(--w), transparent 0 calc(var(--w) + var(--s));
border-radius: 5px;
position: relative;
width: 200px;
height: 200px;
display:inline-block;
border: 1px solid gray;
margin:15px;
clip-path:inset(calc(-1*var(--o)));
}
.outer::before,
.outer::after,
.outer span::before,
.outer span::after {
content:"";
position: absolute;
opacity:0;
transition:1s;
animation: 1s linear infinite;
}
.outer::before,
.outer::after {
height: var(--th);
left: calc(-1*var(--o));
width: calc(100% + var(--w) + var(--s) + 2*var(--o));
background: repeating-linear-gradient(to right, var(--g));
animation-name:drawX;
}
.outer span::before,
.outer span::after {
width: var(--th);
top: calc(-1*var(--o));
height: calc(100% + var(--w) + var(--s) + 2*var(--o));
background: repeating-linear-gradient(to bottom, var(--g));
animation-name:drawY;
}
.outer::before {top: calc(-1*var(--o)); animation-direction:reverse;}
.outer span::before {right: calc(-1*var(--o)); animation-direction:reverse;}
.outer::after { bottom: calc(-1*var(--o));}
.outer span::after { left: calc(-1*var(--o));}
.outer:hover::before,
.outer:hover::after,
.outer:hover span::before,
.outer:hover span::after {
opacity:1;
}
@keyframes drawX {
to {
transform: translateX(calc(-1*(var(--w) + var(--s))));
}
}
@keyframes drawY {
to {
transform: translateY(calc(-1*(var(--w) + var(--s))));
}
}
<div class="outer">
<span></span>
</div>
<div class="outer" style="--th:4px;--o:8px;--s:8px;--w:8px;--c:blue;">
<span></span>
</div>