Loading Underline

loop

An accent bar sweeps back and forth beneath the text forever.

17/120
Align
Ease
Duration
s
0.13
Stagger
s
00.2
Delay
s
02
export function loadingUnderline(el) {
  if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return () => {}

  el.style.position = 'relative'
  el.style.display = 'inline-block'
  const bar = document.createElement('span')
  bar.className = 'k-loop-underline'
  bar.setAttribute('aria-hidden', 'true')
  el.append(bar)
  const easing = 'linear(0.0000,0.0016,0.0065,0.0145,0.0257,0.0400,0.0573,0.0774,0.1003,0.1257,0.1536,0.1838,0.2160,0.2500,0.2857,0.3227,0.3609,0.4000,0.4397,0.4799,0.5201,0.5603,0.6000,0.6391,0.6773,0.7143,0.7500,0.7840,0.8162,0.8464,0.8743,0.8997,0.9226,0.9427,0.9600,0.9743,0.9855,0.9935,0.9984,1.0000)'
  const anim = bar.animate(
    [{ transform: 'translateX(-100%)' }, { transform: 'translateX(100%)' }],
    {
      duration: 1.2 * 1000,
      delay: 0 * 1000,
      easing,
      iterations: Infinity,
      direction: 'alternate',
      fill: 'backwards',
    },
  )
  return () => {
    anim.cancel()
    bar.remove()
    el.style.position = ''
    el.style.display = ''
  }
}

/* CSS */
.k-loop-underline {
  position: absolute;
  inset-inline-start: 0;
  inset-block-end: -4px;
  inline-size: 40%;
  block-size: 2px;
  background: var(--accent);
}