Split Text - Animated Words

Create infinitely animated word effects that respect user's motion preferences.

Full article · Video on YouTube · Source on Github

<p split-by="word" word-animation="trampoline">
  split a paragraph of content 🤘💀
</p>

        @keyframes trampoline {
  0% {
    transform: translateY(100%);
    animation-timing-function: ease-out
  }

  50% {
    transform: translateY(0);
    animation-timing-function: ease-in
  }
}

@media (prefers-reduced-motion:no-preference) {
  [word-animation] {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 1ch
  }

  [word-animation=trampoline]>span {
    display: inline-block;
    transform: translateY(100%);
    animation: trampoline 3s ease calc(var(--index) * 150 * 1ms) infinite alternate
  }
}
        

        const span = (text, index) => {
  const node = document.createElement('span')

  node.textContent = text
  node.style.setProperty('--index', index)
  
  return node
}

export const byWord = text =>
  text.split(' ').map(span)

const {matches:motionOK} = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

if (motionOK) {
  const splitTargets = document.querySelectorAll('[split-by]')

  splitTargets.forEach(node => {
    let nodes = byWord(node.innerText)

    if (nodes)
      node.firstChild.replaceWith(...nodes)
  })
}