Letter by letter
Each character drops in with its own delay, giving a lively, playful headline entrance.
CSSJavaScriptBeginner
<h1 id="h">Bouncy letters</h1>
h1{margin:0;font-size:clamp(2.4rem,10vw,5rem);letter-spacing:-.03em;text-align:center}
.c{display:inline-block;opacity:0;animation:drop .7s cubic-bezier(.34,1.56,.64,1) forwards;animation-delay:calc(var(--i) * 45ms + 150ms)}
@keyframes drop{from{opacity:0;transform:translateY(-.8em) rotate(-8deg)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.c{opacity:1;animation:none}}
const h = document.getElementById('h');
const text = h.textContent;
h.setAttribute('aria-label', text);
h.innerHTML = [...text].map((ch, i) =>
`<span class="c" aria-hidden="true" style="--i:${i}">${ch === ' ' ? ' ' : ch}</span>`).join('');
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Letter by letter</title>
<style>
*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{display:grid;place-items:center;background:#140807;color:#fffffc;font:16px/1.5 system-ui,-apple-system,"Segoe UI",sans-serif}
h1{margin:0;font-size:clamp(2.4rem,10vw,5rem);letter-spacing:-.03em;text-align:center}
.c{display:inline-block;opacity:0;animation:drop .7s cubic-bezier(.34,1.56,.64,1) forwards;animation-delay:calc(var(--i) * 45ms + 150ms)}
@keyframes drop{from{opacity:0;transform:translateY(-.8em) rotate(-8deg)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.c{opacity:1;animation:none}}
</style></head>
<body><h1 id="h">Bouncy letters</h1>
<script>
const h = document.getElementById('h');
const text = h.textContent;
h.setAttribute('aria-label', text);
h.innerHTML = [...text].map((ch, i) =>
`<span class="c" aria-hidden="true" style="--i:${i}">${ch === ' ' ? ' ' : ch}</span>`).join('');
</script>
</body></html>
Good for
Short headings, logos and playful sections. Avoid long paragraphs.
Watch out for
Keep spaces as non-breaking so words do not collapse. Total duration grows with text length, so use only on short strings.
Accessibility
Wrap motion in @media (prefers-reduced-motion: reduce) and switch it off or shorten it for people who ask for less movement.