Использование с ScrollMagic

Библиотека AOS (Animate On Scroll) ориентирована на декларативные CSS-анимации, активируемые при появлении элементов в зоне видимости. В свою очередь, ScrollMagic предоставляет более низкоуровневый контроль над прокруткой: управление сценами, синхронизация с таймлайнами, закрепление (pinning) элементов и сложные сценарии анимации.

Совместное использование позволяет:

  • комбинировать простые декларативные эффекты AOS с программируемой логикой ScrollMagic
  • управлять моментом запуска AOS-анимаций через сцены
  • синхронизировать анимации с прокруткой (progress-based animation)
  • устранять ограничения стандартного поведения AOS (например, при нестандартных контейнерах прокрутки)

Подключение библиотек

<link rel="stylesheet" href="https://unpkg.com/aos@2.3.4/dist/aos.css" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollMagic/2.0.8/ScrollMagic.min.js"></script>
<script src="https://unpkg.com/aos@2.3.4/dist/aos.js"></script>

Инициализация:

AOS.init({
  duration: 800,
  once: false
});

const controller = new ScrollMagic.Controller();

Базовый принцип интеграции

AOS отслеживает появление элементов через собственный обработчик скролла. ScrollMagic работает через сцены (Scene), которые определяют:

  • триггер-элемент
  • точку активации
  • длительность сцены

Чтобы связать их, используется принудительное обновление AOS:

scene.on("enter", () => {
  AOS.refresh();
});

Управление запуском AOS через ScrollMagic

Пример: запуск анимации при достижении сцены

HTML:

<div id="trigger"></div>

<div data-aos="fade-up" id="box">
  Контент
</div>

JS:

const scene = new ScrollMagic.Scene({
  triggerElement: "#trigger",
  triggerHook: 0.8,
  reverse: true
})
.on("enter", () => {
  document.querySelector("#box").classList.add("aos-animate");
})
.on("leave", () => {
  document.querySelector("#box").classList.remove("aos-animate");
})
.addTo(controller);

Объяснение

  • aos-animate — класс, который AOS добавляет автоматически
  • ScrollMagic берет управление на себя и вручную переключает состояние

Отключение автоматического поведения AOS

Чтобы полностью передать контроль ScrollMagic, необходимо отключить автоинициализацию:

AOS.init({
  startEvent: 'DOMContentLoaded',
  disableMutationObserver: true
});

И не использовать стандартный scroll listener AOS, а управлять классами вручную.


Синхронизация анимации с прогрессом прокрутки

ScrollMagic позволяет отслеживать прогресс сцены:

scene.on("progress", (event) => {
  const progress = event.progress;

  const element = document.querySelector("#box");
  element.style.transform = `translateY(${100 - progress * 100}px)`;
  element.style.opacity = progress;
});

Комбинация с AOS

AOS задает начальные стили, ScrollMagic — управляет переходом:

[data-aos="custom"] {
  opacity: 0;
  transform: translateY(100px);
  transition: all 0.3s ease;
}
scene.on("progress", (event) => {
  const el = document.querySelector("[data-aos='custom']");
  el.style.opacity = event.progress;
});

Использование pinning вместе с AOS

ScrollMagic поддерживает закрепление элементов:

new ScrollMagic.Scene({
  triggerElement: "#section",
  duration: 500
})
.setPin("#pinned-element")
.addTo(controller);

Влияние на AOS

При использовании pin:

  • элемент может не попадать в viewport стандартным способом
  • AOS может не срабатывать

Решение

Принудительное обновление:

scene.on("enter", () => AOS.refreshHard());

Работа с кастомными контейнерами прокрутки

AOS по умолчанию работает с window. ScrollMagic позволяет использовать кастомный контейнер:

const controller = new ScrollMagic.Controller({
  container: "#scroll-container"
});

Проблема

AOS не отслеживает кастомные контейнеры.

Решение

Принудительный вызов обновления:

document.querySelector("#scroll-container").addEventListener("scroll", () => {
  AOS.refresh();
});

Перезапуск анимаций

AOS поддерживает повторное воспроизведение, но при интеграции со ScrollMagic это нужно контролировать явно:

scene.on("leave", () => {
  const el = document.querySelector("#box");
  el.classList.remove("aos-animate");
});

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

Минимизация вызовов AOS.refresh()

Частые вызовы приводят к перерасчету layout:

let ticking = false;

window.addEventListener("scroll", () => {
  if (!ticking) {
    requestAnimationFrame(() => {
      AOS.refresh();
      ticking = false;
    });
    ticking = true;
  }
});

Ограничение количества сцен

Каждая сцена ScrollMagic:

  • добавляет слушатели
  • увеличивает нагрузку на scroll

Рекомендуется:

  • группировать элементы
  • использовать один триггер для нескольких анимаций

Использование с GSAP через ScrollMagic

ScrollMagic часто используется вместе с GSAP. В этом случае AOS может выполнять роль “простых” эффектов, а GSAP — сложных.

const tween = gsap.to("#box", {
  x: 200,
  opacity: 1
});

new ScrollMagic.Scene({
  triggerElement: "#box",
  duration: 300
})
.setTween(tween)
.addTo(controller);

Смешанный подход

  • AOS — для появления элементов
  • GSAP + ScrollMagic — для сложной логики

Частые проблемы и их устранение

Анимации не срабатывают

Причины:

  • элемент уже в зоне видимости при загрузке
  • ScrollMagic изменяет поток документа
  • неправильный triggerHook

Решение:

AOS.refreshHard();

Дёргание анимаций

Причины:

  • конфликт transform между AOS и ScrollMagic
  • частые изменения стилей

Решение:

  • разделить зоны ответственности
  • избегать одновременного управления transform

Несовпадение таймингов

AOS использует CSS transition, ScrollMagic — JS.

Решение:

  • синхронизировать длительности вручную
  • использовать easing функции одинакового типа

Паттерны использования

1. AOS как триггер, ScrollMagic как контроллер

  • AOS определяет стили
  • ScrollMagic управляет моментом запуска

2. ScrollMagic как основной двигатель

  • AOS используется только для начальных состояний
  • вся логика — через progress

3. Гибридный подход

  • простые элементы → AOS
  • сложные секции → ScrollMagic

Рекомендации по архитектуре

  • не смешивать управление одними и теми же CSS-свойствами
  • использовать data-атрибуты AOS только для декларации
  • переносить сложную логику в ScrollMagic
  • минимизировать количество пересчетов layout
  • избегать глубоких вложенных сцен

Пример комплексной реализации

<section id="section">
  <div id="trigger"></div>

  <div id="box" data-aos="fade-up">
    Контент
  </div>
</section>
AOS.init({
  duration: 600,
  once: false
});

const controller = new ScrollMagic.Controller();

const scene = new ScrollMagic.Scene({
  triggerElement: "#trigger",
  duration: 400,
  triggerHook: 0.7
})
.on("enter", () => {
  document.querySelector("#box").classList.add("aos-animate");
})
.on("progress", (e) => {
  const el = document.querySelector("#box");
  el.style.transform = `scale(${0.8 + e.progress * 0.2})`;
})
.on("leave", () => {
  document.querySelector("#box").classList.remove("aos-animate");
})
.addTo(controller);

В данной конфигурации:

  • AOS отвечает за появление (fade-up)
  • ScrollMagic управляет масштабом и жизненным циклом анимации
  • достигается точный контроль без потери удобства декларативных эффектов