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

Для того, чтобы нарисовать радугу, мы могли бы использовать линейный градиент, с резкими переходами, тот же способ, что и при рисовании полос в 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, что бы избежать этого бага. Я оставлю коментарий про это в коде, но сам код изменять не буду, чтобы сохранить первоначальный вариант.