Один из самых популярных эффектов анимации уходящего года — это эффект чтения текста. То есть при прокручивании страницы цвет текста меняется постепенно, создавая иллюзию, что вы прочитали текст (прокрутите вниз):

Для начала создадим наш блок с текстом:

<div class="wrap">

   <div class="animation">
      <p class="textScroll">Это нормально – завершать отношения и работы, которые больше ничего не дают. Которым больше ничего не можете дать вы. Не потому что с другими людьми или в другом месте будет ярче и интереснее, а потому что конкретно здесь  ярче и интереснее уже точно не будет. (с)</p>
   </div>
        
</div>

Далее добавим стили.
Оформление сделаю максимально простым, ведь здесь главное показать сам эффект.

body {
    background: #131313;
    font-family: 'Golos Text', sans-serif;
    color: #fff;
    position: relative;
    z-index: 1;
}

.wrap {
    width: 90%;
    margin-left: auto;
    margin-right: auto;
    display: flex;
    flex-direction:column;
    align-items: start;
    justify-content: center;
    gap: 40px;
    position: relative;
    z-index: 3;
}

h1  {
    font-family: 'Golos Text', sans-serif;
    font-size: 300px;
    font-weight: 400;
}

.animation {
    width: 64%;
    margin: 30% auto;
}

.textScroll {
    font-size: clamp(32px, 5vw, 65px);
    text-align: center;
}

Подключим необходимые скрипты:

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.4/gsap.min.js"></script>
<script src="https://unpkg.com/split-type"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.4/ScrollTrigger.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.2/TextPlugin.min.js"></script>

Где:

  • gsap.min.js — это библиотека анимации
  • ScrollTrigger.min.js — плагин для GSAP, с помощью него создаем анимацию при прокрутке
  • TextPlugin.min.js — плагин для GSAP, позволяет превращать одну строку DOM-элемента в другую, последовательно заменяя отдельные буквы, с помощью нее будут перекрашиваться наши буквы.
  • split-type — разбивает строку на слова.

Итак приступим к написанию самого скрипта:

Находим все элементы с классом textScroll и сохраняем их в переменной splitTypes:
const splitTypes = document.querySelectorAll(".textScroll");

Для каждого элемента в splitTypes выполняем функцию.
splitTypes.forEach((char, i) => { ... });

В нашем случае существует только один .textScroll:

Далее мы задали настройки цветов, где bg — первоначальный цвет текста, а fg — цвет, в который будет перекрашиваться текст.
const bg = "rgb(255 255 255 / 17%)";
const fg = "#fff";

Далее разделили текст на слова:
const text = new SplitType(char, { types: "words" });

SplitType разбивает текст внутри элемента на слова, оборачивая каждое слово в отдельный HTML-элемент, например:

<div class="word">Это</div> <div class="word">нормально</div>

Потом анимируем текст с помощью GSAP:

gsap.fromTo(
    text.words, 
    { color: bg },
    {
        color: fg,
        duration: 0.3,
        stagger: 0.2,
        opacity: 1,
        scrollTrigger: { ... }
    }
);

text.words: массив слов, на который применяются анимации. fromTo: задает начальные ({ color: bg }) и конечные ({ color: fg, ... }) состояния.

  • duration: продолжительность анимации каждого слова (0.3 сек).
  • stagger: задержка между началом анимации для каждого слова (0.2 сек).
  • opacity: 1: слова становятся полностью видимыми.

Далее задействуем библиотеку ScrollTrigger для реализации нашей анимации при скролле:

scrollTrigger: {
    trigger: char,
    start: "top center",
    end: "bottom center",
    scrub: 1,
    markers: false,
    toggleActions: "play play reverse reverse"
}
  • trigger — активируем анимацию, когда char (элемент .textScroll) появляется в зоне видимости
  • start: "top center" — указываем начало анимации, у нас это начало идет, когда верхняя граница элемента доходит до центра нашего экрана
  • end: "bottom center" — указываем окончание анимации, у нас она заканчивается, когда нижняя граница элемента доходит до центра экрана
  • scrub: 1 — плавный переход анимации при скролле
  • markers: false — отключаем маркеры (если их включить они покажут границы начала и окончания анимации)
  • toggleActions: "play play reverse reverse" — задаем поведение запуска анимации и ее повторения

Скрипт полностью:

const splitTypes = document.querySelectorAll(".textScroll");

splitTypes.forEach((char, i) => {

    const bg = "rgb(255 255 255 / 17%)";
    const fg = "#fff";

    const text = new SplitType(char, { types: "words" });

    gsap.fromTo(
        text.words, 
        {
            color: bg
        },
        {
            color: fg,
            duration: 0.3,
            stagger: 0.2,
            opacity: 1,
            scrollTrigger: {
                trigger: char,
                start: "top center",
                end: "bottom center",
                scrub: 1,
                markers: false,
                toggleActions: "play play reverse reverse"
            }
        }
    );
});