The outline melts between organic blob shapes while a thinner echo trails a few seconds behind. Only border-radius animates, eight values per shape, so the box never changes size or shifts layout.
Also known as: animate border radius css, css border radius animation, blob border animation.
<div class="bdr-blob-border">Organic</div>
.bdr-blob-border {
--c: var(--bdr-color, #3b82f6);
font-size: var(--bdr-size, 16px);
position: relative;
display: grid;
place-items: center;
width: 15em;
height: 8.5em;
border-radius: 1em;
font-family: system-ui, sans-serif;
font-weight: 600;
box-sizing: border-box;
border: 0.14em solid var(--c);
background: color-mix(in srgb, var(--c) 8%, transparent);
box-shadow: 0 0 1.2em color-mix(in srgb, var(--c) 25%, transparent);
animation: bdr-blob-border-morph 9s ease-in-out infinite;
}
.bdr-blob-border::before {
content: "";
position: absolute;
inset: -0.5em;
border: 1px solid color-mix(in srgb, var(--c) 50%, transparent);
pointer-events: none;
animation: bdr-blob-border-morph 9s ease-in-out -6.8s infinite;
}
@keyframes bdr-blob-border-morph {
0%, 100% { border-radius: 38% 62% 66% 34% / 52% 34% 66% 48%; }
25% { border-radius: 70% 30% 38% 62% / 30% 62% 38% 70%; }
50% { border-radius: 30% 70% 62% 38% / 66% 30% 70% 34%; }
75% { border-radius: 62% 38% 28% 72% / 40% 70% 30% 60%; }
}
@media (prefers-reduced-motion: reduce) {
.bdr-blob-border, .bdr-blob-border *, .bdr-blob-border::before, .bdr-blob-border::after, .bdr-blob-border *::before, .bdr-blob-border *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--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.