A cup on a saucer with three wisps of steam that curl up and fade in turn. The cup is two pseudo-elements; the steam is SVG paths animated with stroke-dashoffset.
Also known as: coffee loading animation, steaming cup loader, coffee break loader.
<div class="ldr-coffee-cup" role="status" aria-label="Loading">
<svg class="ldr-coffee-cup-steam" viewBox="0 0 28 22" aria-hidden="true">
<path d="M8 21c-3.5-4 3.5-6 0-10.5s3.5-6 0-9.5" pathLength="10"/>
<path d="M14 21c-3.5-4 3.5-6 0-10.5s3.5-6 0-9.5" pathLength="10"/>
<path d="M20 21c-3.5-4 3.5-6 0-10.5s3.5-6 0-9.5" pathLength="10"/>
</svg>
<span class="ldr-coffee-cup-saucer"></span>
</div>.ldr-coffee-cup {
--s: var(--ldr-size, 48px);
--c: var(--ldr-color, #3b82f6);
position: relative;
width: var(--s);
height: var(--s);
}
.ldr-coffee-cup::before {
content: "";
position: absolute;
left: 14%;
bottom: 16%;
width: 56%;
height: 40%;
border-radius: 6% 6% 45% 45% / 8% 8% 60% 60%;
background: var(--c);
}
.ldr-coffee-cup::after {
content: "";
position: absolute;
left: 60%;
bottom: 28%;
width: 26%;
height: 24%;
box-sizing: border-box;
border: calc(var(--s) / 14) solid var(--c);
border-radius: 50%;
}
.ldr-coffee-cup-saucer {
position: absolute;
left: 6%;
bottom: 9%;
width: 72%;
height: calc(var(--s) / 14);
border-radius: var(--s);
background: var(--c);
}
.ldr-coffee-cup-steam {
position: absolute;
left: 14%;
top: 0;
width: 56%;
height: 44%;
fill: none;
stroke: var(--c);
stroke-width: 2.6;
stroke-linecap: round;
}
.ldr-coffee-cup-steam path {
stroke-dasharray: 7 10;
stroke-dashoffset: 7;
animation: ldr-coffee-cup-rise 2.2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
.ldr-coffee-cup-steam path:nth-child(2) { animation-delay: -0.4s; }
.ldr-coffee-cup-steam path:nth-child(3) { animation-delay: -0.15s; }
@keyframes ldr-coffee-cup-rise {
0% { stroke-dashoffset: 7; opacity: 0; }
25% { opacity: 1; }
60% { opacity: 0.9; }
100% { stroke-dashoffset: -10; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.ldr-coffee-cup, .ldr-coffee-cup *, .ldr-coffee-cup::before, .ldr-coffee-cup::after, .ldr-coffee-cup *::before, .ldr-coffee-cup *::after {
animation-duration: 3s;
}
}--ldr-color on the element or a parent.
Currently previewing #3b82f6.--ldr-size. Every dimension in the snippet is
derived from it. Currently previewing 64px.animation shorthand.
Delays on the children are relative, so they keep their rhythm.role="status" and an
aria-label so screen readers announce the wait. The reduced-motion rule
at the end slows the animation for users who asked for less motion.