Мне очень нравится дизайн сайта Sandwich. Среди множества красивых эффектов, у них есть заголовки с подчеркиванием в виде радуги, которая сдвигается при прокрутке. И этот небольшой эффект вычисляется не по скроллу, а его движение зависит от положения прокрутки.

Rainbow demo

Для того, чтобы нарисовать радугу, мы могли бы использовать линейный градиент, с резкими переходами, тот же способ, что и при рисовании полос в CSS. Это довольно большой кусок проверенного CSS, который работает стабильно, но я вижу, что вместо этого они выбрали фоновое изображение. Это SVG изображение можно посмотреть здесь. Оно весит всего 661 байт и это очень мало. Мы можем сделать это изображение похожим на подчеркивание ограничив высоту с помощью background-size и расположив его под текстом с помощью свойства background-position.

Мы будем делать это на вложенном инлайновом элементе, чтобы подчеркивание переносилось там, где переносятся слова.

h1 span {
  background-image: url(rainbow.svg);
  background-repeat: repeat-x;
  background-size: 100vw 0.2em;
  background-position: left bottom 5px;
}

Чтобы получить анимацию, мы будем изменять значение background-position-x. Не самое производительное свойство для анимаций, но мы не анимируем изображение в полном смысле этого слова, а всего-лишь сдвигаем его в зависимости от положения прокрутки. Вместо того, чтобы вручную управлять свойством background-position-x, мы зададим его с помощью кастомного CSS свойства, а затем будем обрабатывать с помощью JavaScript.

background-position-x: var(--scrollPos);

Обновлять эту переменную во время прокрутки страницы очень просто:

window.addEventListener("scroll", e => {
  let scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
  let newPos = scrollTop + "px";
  document.documentElement.style.setProperty('--scrollPos', newPos);
});

И это работает!

Видите что-то вроде “артефактной” линии там, где я использую document.body или document.documentElement? Это дурацкий кроссбраузерный баг, из-за того, что реализация “элемента прокрутки” в Safari отличается от ее реализации в остальных браузерах.

Пока я делал этот пример, я узнал, что можно использовать document.scrollingElement, что бы избежать этого бага. Я оставлю коментарий про это в коде, но сам код изменять не буду, чтобы сохранить первоначальный вариант.