Анимация скролла

Anime.js предоставляет мощные средства для создания анимации элементов на странице, управляемой скроллом. Для реализации такого эффекта необходимо комбинировать возможности anime.js с событиями прокрутки браузера. Основной подход заключается в изменении свойств объектов в зависимости от текущей позиции скролла, что позволяет создавать плавные и интерактивные переходы.

Получение позиции скролла

Для отслеживания скролла используется объект window и событие scroll:

window.addEventListener('scroll', () => {
    const scrollY = window.scrollY || window.pageYOffset;
});

Переменная scrollY хранит текущее смещение страницы по вертикали. Это значение становится ключевым параметром для вычисления прогресса анимации.

Использование anime.js для управления анимацией

В отличие от классических анимаций, управляемых таймером или циклом, анимация скролла требует прямой связи со значением прокрутки. Например, для изменения прозрачности элемента в зависимости от скролла можно использовать следующую конструкцию:

const box = document.querySelector('.box');

window.addEventListener('scroll', () => {
    const scrollY = window.scrollY;
    const progress = Math.min(scrollY / 500, 1); // нормализуем значение до 0–1

    anime({
        targets: box,
        opacity: progress,
        duration: 0,
        easing: 'linear'
    });
});

Ключевые моменты:

  • duration: 0 гарантирует мгновенное обновление значения без задержки, чтобы анимация точно соответствовала скроллу.
  • progress вычисляется как отношение текущего скролла к заданной длине анимации, что позволяет создавать динамические эффекты на всей странице.

Анимация трансформаций

Для придания более выразительных эффектов используют CSS-трансформации:

window.addEventListener('scroll', () => {
    const scrollY = window.scrollY;
    const progress = Math.min(scrollY / 800, 1);

    anime({
        targets: box,
        translateX: progress * 300, // смещение по X
        rotate: progress * 360,     // вращение
        scale: 1 + progress * 0.5,
        duration: 0,
        easing: 'linear'
    });
});

Особенности:

  • Использование множителя progress позволяет плавно масштабировать, вращать и перемещать элементы.
  • Применение duration: 0 делает анимацию «жестко привязанной» к скроллу, без временной интерполяции.

Связывание нескольких анимаций

Для сложных интерфейсов часто требуется запуск нескольких анимаций одновременно при скролле. Это реализуется через массив targets или независимые вызовы anime():

const items = document.querySelectorAll('.item');

window.addEventListener('scroll', () => {
    const scrollY = window.scrollY;
    const progress = Math.min(scrollY / 1000, 1);

    items.forEach((item, index) => {
        anime({
            targets: item,
            translateY: progress * 50 * (index + 1),
            opacity: progress,
            duration: 0,
            easing: 'linear'
        });
    });
});

Преимущества:

  • Индекс элемента позволяет создавать эффект последовательного появления.
  • Простое масштабирование и смещение обеспечивают разнообразие анимаций без сложной логики.

Оптимизация производительности

Анимации на скролле могут нагрузить браузер. Для повышения производительности используют:

  1. requestAnimationFrame для синхронизации обновлений с кадрами рендеринга:
let ticking = false;

window.addEventListener('scroll', () => {
    if (!ticking) {
        window.requestAnimationFrame(() => {
            const scrollY = window.scrollY;
            const progress = Math.min(scrollY / 500, 1);

            anime({
                targets: box,
                translateY: progress * 200,
                opacity: progress,
                duration: 0,
                easing: 'linear'
            });

            ticking = false;
        });
        ticking = true;
    }
});
  1. Минимизация количества элементов в targets, анимация которых происходит одновременно.
  2. Кэширование DOM-элементов перед запуском скрипта.

Применение анимации к якорям и секциям

Для эффектов «входа в экран» элементов используют проверку положения относительно окна:

const sections = document.querySelectorAll('.section');

function animateSections() {
    const windowHeight = window.innerHeight;

    sections.forEach(section => {
        const rect = section.getBoundingClientRect();
        const progress = Math.min(Math.max((windowHeight - rect.top) / windowHeight, 0), 1);

        anime({
            targets: section,
            translateY: 50 * (1 - progress),
            opacity: progress,
            duration: 0,
            easing: 'linear'
        });
    });
}

window.addEventListener('scroll', animateSections);
animateSections();

Пояснения:

  • getBoundingClientRect() позволяет вычислить, насколько элемент видим в текущем окне.
  • Прогресс ограничивается от 0 до 1 для корректной интерполяции.
  • Эффект создаёт плавное появление с нижнего края при прокрутке.

Совмещение с библиотеками прокрутки

Anime.js отлично интегрируется с библиотеками, которые управляют скроллом, такими как Locomotive Scroll или GSAP ScrollTrigger. В таких случаях значения скролла получают из API этих библиотек, но логика применения к anime() остаётся идентичной: вычисление прогресса → обновление свойств элементов мгновенно.