← Text effects

Gradient Sweep

A band of colours flows continuously through the letters, like light moving through liquid. It loops seamlessly and rests while the text is off screen.

Colour in motion

How to use it

  1. Paste the snippet just before </head>.
  2. Add data-gradient-sweep to any heading or text element.

Options

Add any of these attributes to the same element.

data-colorsColours to flow through, comma separated. Default purple, pink and amber.
data-speedTime for the colours to travel one full cycle. Default 4000 ms.
data-directionright (default) or left.

The gradient replaces the text’s colour. With reduced motion turned on it stays put.

1 · Snippet
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bundles/anime.umd.min.js"></script>
<script>
  (function () {
    // Gradient Sweep: a band of colours flows continuously through the letters,
    // like light moving through liquid. Keeps going while the text is on screen.
    // Usage: <h1 data-gradient-sweep>Full spectrum</h1>
    // Optional: data-colors (comma separated; default purple, pink, amber),
    // data-speed (ms for the colours to travel one full cycle; default 4000),
    // data-direction ("right", the default, or "left").
    var DEFAULTS = { colors: '#6a0dad, #ec4899, #f59e0b', speed: 4000 };

    var css =
      '.gsw{background-repeat:repeat-x;background-size:200% 100%;-webkit-background-clip:text;background-clip:text;' +
      '-webkit-text-fill-color:transparent;color:transparent;-webkit-box-decoration-break:clone;box-decoration-break:clone}';
    var style = document.createElement('style');
    style.textContent = css;
    document.head.appendChild(style);

    function paint(el) {
      var colors = (el.dataset.colors || DEFAULTS.colors).split(',').map(function (c) { return c.trim(); });
      // The gradient is two text-widths long and ends on the colour it starts
      // with, so it tiles seamlessly as it slides.
      el.style.backgroundImage = 'linear-gradient(90deg, ' + colors.concat(colors[0]).join(', ') + ')';
      el.classList.add('gsw');
    }

    function start(el) {
      var d = el.dataset;
      // With a 200% wide background, shifting the position by 200% moves it
      // exactly one tile.
      var shift = d.direction === 'left' ? ['0% 50%', '200% 50%'] : ['200% 50%', '0% 50%'];
      return anime.animate(el, {
        backgroundPosition: shift,
        duration: +d.speed || DEFAULTS.speed,
        ease: 'linear',
        loop: true
      });
    }

    function init() {
      var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
      document.querySelectorAll('[data-gradient-sweep]').forEach(function (el) {
        if (el._gsw) return;
        el._gsw = true;
        paint(el);
        // Reduced motion: the gradient stays still.
        if (reduced) return;
        var anim = null;
        // Only flow while visible, to save battery.
        new IntersectionObserver(function (entries) {
          if (!entries[0].isIntersecting) { if (anim) anim.pause(); return; }
          if (anim) anim.play();
          else anim = start(el);
        }).observe(el);
      });
    }

    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
    else init();
  })();
</script>
2 · Your HTML
<h1 data-gradient-sweep>Colour in motion</h1>

<!-- your own colours, flowing left: -->
<h1 data-gradient-sweep data-colors="#0ea5e9, #a855f7, #ec4899" data-direction="left">Colour in motion</h1>