A round avatar inside a spinning gradient ring with a clean gap, like an unwatched story. The ring is a conic layer cut by a radial mask, so the gap stays transparent on any background.
Also known as: instagram story ring css, gradient avatar border, avatar ring animation css.
<div class="bdr-story-ring-border"> <span class="bdr-story-ring-border-ring"><span class="bdr-story-ring-border-photo" role="img" aria-label="Profile photo"></span></span> <span class="bdr-story-ring-border-name">your story</span> </div>
.bdr-story-ring-border {
--c: var(--bdr-color, #3b82f6);
font-size: var(--bdr-size, 16px);
display: inline-grid;
justify-items: center;
gap: 0.5em;
font-family: system-ui, sans-serif;
}
.bdr-story-ring-border-ring {
position: relative;
display: grid;
place-items: center;
width: 5.5em;
height: 5.5em;
}
.bdr-story-ring-border-ring::before {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
background: conic-gradient(#feda75, #fa7e1e, #d62976, #962fbf, #4f5bd5, #feda75);
-webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 0.27em), #000 calc(100% - 0.25em));
mask: radial-gradient(farthest-side, transparent calc(100% - 0.27em), #000 calc(100% - 0.25em));
animation: bdr-story-ring-border-spin 3s linear infinite;
}
.bdr-story-ring-border-photo {
--skin: color-mix(in srgb, var(--c) 18%, #fff);
width: calc(100% - 0.85em);
height: calc(100% - 0.85em);
border-radius: 50%;
background:
radial-gradient(circle at 50% 40%, var(--skin) 0 17%, transparent 18%),
radial-gradient(34% 30% at 50% 98%, var(--skin) 0 98%, transparent 100%),
linear-gradient(160deg, color-mix(in srgb, var(--c) 50%, #fff), var(--c));
}
.bdr-story-ring-border-name {
font-size: 0.85em;
font-weight: 500;
}
@keyframes bdr-story-ring-border-spin {
to { transform: rotate(1turn); }
}
@media (prefers-reduced-motion: reduce) {
.bdr-story-ring-border, .bdr-story-ring-border *, .bdr-story-ring-border::before, .bdr-story-ring-border::after, .bdr-story-ring-border *::before, .bdr-story-ring-border *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}The same effect using Tailwind utility classes. No custom CSS or config needed.
<div class="inline-grid justify-items-center gap-2">
<div class="relative grid h-[5.5em] w-[5.5em] place-items-center">
<div class="absolute inset-0 animate-spin rounded-full bg-[conic-gradient(#feda75,#fa7e1e,#d62976,#962fbf,#4f5bd5,#feda75)] [animation-duration:3s] [mask:radial-gradient(farthest-side,transparent_calc(100%-4px),#000_calc(100%-3px))]"></div>
<div class="h-[calc(100%-0.85em)] w-[calc(100%-0.85em)] rounded-full bg-gradient-to-br from-blue-300 to-blue-500" role="img" aria-label="Profile photo"></div>
</div>
<span class="text-sm font-medium">your story</span>
</div>--bdr-color on the element or a parent.
Currently previewing #3b82f6.--bdr-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.