Определение позиции скролла

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

В контексте Velocity.js работа с прокруткой обычно делится на два уровня: получение текущего значения scroll и использование этого значения как условия или параметра для анимации.


Базовые способы определения scroll-позиции

Для окна браузера наиболее распространённые источники данных:

const scrollTop = window.pageYOffset;

Альтернативный вариант с поддержкой старых браузеров:

const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

Горизонтальная позиция:

const scrollLeft = window.pageXOffset;

Эти значения обновляются при каждом событии прокрутки и используются как опорная точка для логики интерфейса.


Использование события scroll

Событие прокрутки является основным механизмом отслеживания изменения позиции:

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

При высокой частоте вызовов важно учитывать производительность, так как scroll генерирует большое количество событий в секунду. В подобных случаях часто применяется throttling или requestAnimationFrame.


Привязка scroll к анимациям Velocity.js

Velocity.js предоставляет встроенную поддержку анимации прокрутки через специальную команду scroll.

Базовый пример плавной прокрутки к элементу:

Velocity(document.body, "scroll", {
  duration: 800,
  offset: -100,
  easing: "easeInOutQuart"
});

Параметр offset позволяет скорректировать финальную позицию, например, для учёта фиксированной шапки интерфейса.


Получение текущей позиции как управляющего параметра

Scroll-позиция часто используется не для самой прокрутки, а для вычисления состояния интерфейса:

const scrollTop = window.pageYOffset;

if (scrollTop > 300) {
  Velocity(element, { opacity: 1, translateY: 0 }, { duration: 300 });
} else {
  Velocity(element, { opacity: 0, translateY: 20 }, { duration: 300 });
}

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


Плавная синхронизация через requestAnimationFrame

Для минимизации нагрузки scroll-события часто заменяются циклом анимации:

function update() {
  const scrollTop = window.pageYOffset;

  element.style.transform = `translateY(${scrollTop * 0.2}px)`;

  requestAnimationFrame(update);
}

update();

Хотя сам Velocity.js не требует такого подхода для базовых анимаций, подобная схема используется при сложных интерфейсах с параллакс-эффектами.


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

Параллакс-эффект формируется за счёт разной скорости движения слоёв относительно scrollTop:

window.addEventListener('scroll', () => {
  const scrollTop = window.pageYOffset;

  Velocity(background, {
    translateY: scrollTop * 0.3
  }, {
    duration: 0
  });

  Velocity(foreground, {
    translateY: scrollTop * 0.6
  }, {
    duration: 0
  });
});

Здесь скорость движения задаётся коэффициентом, связанным с текущей позицией прокрутки.


Определение позиции внутри контейнеров

Если прокрутка происходит внутри блока, используется свойство scrollTop самого элемента:

const container = document.querySelector('.scroll-container');

container.addEventListener('scroll', () => {
  const position = container.scrollTop;
});

В таких сценариях Velocity работает с тем же принципом, но анимация применяется к конкретному DOM-элементу вместо окна.


Сопоставление scroll-позиции с прогрессом анимации

Часто scroll нормализуется в диапазон от 0 до 1:

const maxScroll = document.body.scrollHeight - window.innerHeight;
const progress = window.pageYOffset / maxScroll;

Это значение удобно использовать для управления параметрами анимации:

Velocity(element, {
  opacity: progress,
  scale: 0.5 + progress * 0.5
}, {
  duration: 0
});

Использование scroll как триггера состояний

Scroll-позиция часто применяется для построения систем состояний интерфейса:

window.addEventListener('scroll', () => {
  const scrollTop = window.pageYOffset;

  switch (true) {
    case scrollTop < 200:
      Velocity(header, { height: "120px" }, { duration: 300 });
      break;

    case scrollTop < 600:
      Velocity(header, { height: "80px" }, { duration: 300 });
      break;

    default:
      Velocity(header, { height: "60px" }, { duration: 300 });
  }
});

Такой подход позволяет строить адаптивные интерфейсы, реагирующие на глубину просмотра страницы.


Синхронизация scroll и очередей анимаций

Velocity.js использует очередь анимаций, что позволяет связывать прокрутку с последовательными эффектами:

Velocity(element, "scroll", {
  duration: 600
}).then(() => {
  Velocity(element, { opacity: 1 }, { duration: 300 });
});

Так формируется цепочка: сначала изменение позиции, затем визуальный эффект.


Контроль резких скачков позиции

При программной прокрутке возможно резкое изменение scrollTop, которое влияет на интерфейс. Для стабилизации используется фильтрация:

let lastScroll = 0;

window.addEventListener('scroll', () => {
  const current = window.pageYOffset;

  const delta = current - lastScroll;

  if (Math.abs(delta) > 50) {
    Velocity(element, { translateY: delta }, { duration: 200 });
  }

  lastScroll = current;
});

Связь scroll и фиксированных интерфейсных элементов

Фиксированные элементы часто меняют состояние в зависимости от позиции:

window.addEventListener('scroll', () => {
  const scrollTop = window.pageYOffset;

  Velocity(navbar, {
    boxShadow: scrollTop > 100 ? "0 2px 10px rgba(0,0,0,0.2)" : "none"
  }, {
    duration: 200
  });
});

Использование scroll-позиции для ленивых анимаций

Анимации, запускаемые при достижении определённой позиции:

window.addEventListener('scroll', () => {
  const scrollTop = window.pageYOffset;

  if (scrollTop > section.offsetTop - window.innerHeight / 2) {
    Velocity(section, { opacity: 1, translateY: 0 }, { duration: 500 });
  }
});

Подобные конструкции часто используются для постепенного раскрытия контента при прокрутке.