<main>
<div class="list">
<div class="list__item">
<div class="circle">
<svg viewBox="0 0 52 52" class="circle-back">
<circle cx="26" cy="26" r="25" />
</svg>
<svg viewBox="0 0 52 52" class="circle-front">
<circle cx="26" cy="26" r="25" />
</svg>
<span class="dot"></span>
</div>
</div>
<div class="list__item">
<div class="circle">
<svg viewBox="0 0 52 52" class="circle-back">
<circle cx="26" cy="26" r="25" />
</svg>
<svg viewBox="0 0 52 52" class="circle-front">
<circle cx="26" cy="26" r="25" />
</svg>
<span class="dot"></span>
</div>
</div>
<div class="list__item">
<div class="circle">
<svg viewBox="0 0 52 52" class="circle-back">
<circle cx="26" cy="26" r="25" />
</svg>
<svg viewBox="0 0 52 52" class="circle-front">
<circle cx="26" cy="26" r="25" />
</svg>
<span class="dot"></span>
</div>
</div>
<div class="list__item">
<div class="circle">
<svg viewBox="0 0 52 52" class="circle-back">
<circle cx="26" cy="26" r="25" />
</svg>
<svg viewBox="0 0 52 52" class="circle-front">
<circle cx="26" cy="26" r="25" />
</svg>
<span class="dot"></span>
</div>
</div>
<div class="list__item">
<div class="circle">
<svg viewBox="0 0 52 52" class="circle-back">
<circle cx="26" cy="26" r="25" />
</svg>
<svg viewBox="0 0 52 52" class="circle-front">
<circle cx="26" cy="26" r="25" />
</svg>
<span class="dot"></span>
</div>
</div>
</div>
</main>
<style>
:root {
--color: #333;
--inactive-color: rgb(211, 211, 211);
--stroke-width: 2;
}
.list {
display: flex;
}
.list__item {
margin-right: 12px;
}
.list__item:last-child {
margin-right: 0;
}
.circle {
position: relative;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
width: 40px;
height: 40px;
}
.circle-back {
position: absolute;
inset: 0;
color: var(--inactive-color);
stroke: currentColor;
stroke-width: var(--stroke-width);
fill: none;
}
.circle-front {
position: absolute;
inset: 0;
color: var(--color);
stroke: currentColor;
stroke-width: var(--stroke-width);
fill: none;
/* Make the start of the animation visible from above. */
transform: rotate(-90deg);
/* */
stroke-dasharray: 157 157;
stroke-dashoffset: -157;
transition: stroke-dashoffset ease-in-out 500ms;
}
.circle.active .circle-front {
/* Animate with keyframes instead of transition. */
transition: none;
/* Indication of 0% progress. */
stroke-dasharray: 0 157;
stroke-dashoffset: 0;
animation: spin 3s linear;
animation-fill-mode: forwards;
}
.dot {
display: block;
width: 8px;
height: 8px;
background: var(--inactive-color);
border-radius: 8px;
}
.circle.active .dot {
background: var(--color);
}
@keyframes spin {
from {
stroke-dasharray: 0 157;
}
to {
stroke-dasharray: 157 157;
}
}
</style>
<script>
const list = document.querySelectorAll(".circle");
const length = list.length;
let index = 0;
change();
setInterval(() => {
index = (index + 1) % length;
change();
}, 3000);
function change() {
list.forEach((item, i) => {
if (i === index) {
item.classList.add("active");
} else {
item.classList.remove("active");
}
});
}
</script>