Множественные области прокрутки

Headroom.js — это лёгкая библиотека JavaScript, предназначенная для управления видимостью элементов при прокрутке страницы. Основная концепция заключается в том, чтобы скрывать элемент при прокрутке вниз и показывать его при прокрутке вверх. В стандартной конфигурации библиотека ориентируется на глобальную область прокрутки окна window. Однако в современных веб-приложениях часто встречаются множественные прокручиваемые контейнеры, и для корректной работы Headroom.js требуется адаптация под эти условия.


Настройка Headroom для конкретного контейнера

Для того чтобы Headroom.js работал с кастомным контейнером, необходимо использовать параметр scroll при инициализации. По умолчанию Headroom слушает события scroll глобального окна, но можно передать любой DOM-элемент с возможностью прокрутки:

const header = document.querySelector('.header');
const container = document.querySelector('.scrollable-container');

const headroom = new Headroom(header, {
  scroll: container,
  tolerance: {
    up: 10,
    down: 10
  },
  offset: 50,
  classes: {
    initial: 'headroom',
    pinned: 'headroom--pinned',
    unpinned: 'headroom--unpinned',
    top: 'headroom--top',
    notTop: 'headroom--not-top',
    bottom: 'headroom--bottom',
    notBottom: 'headroom--not-bottom'
  }
});

headroom.init();

В этом примере:

  • scroll указывает элемент контейнера, события scroll которого будут отслеживаться.
  • tolerance задаёт порог движения для активации скрытия или отображения.
  • offset определяет расстояние от верхней границы контейнера, после которого активируется логика скрытия/показа.

Управление несколькими контейнерами одновременно

При наличии нескольких областей прокрутки (например, боковая панель и основное содержимое), можно создать несколько экземпляров Headroom.js для каждого контейнера:

const mainHeader = document.querySelector('.main-header');
const sideHeader = document.querySelector('.side-header');

const mainHeadroom = new Headroom(mainHeader, { scroll: document.querySelector('.main-content') });
const sideHeadroom = new Headroom(sideHeader, { scroll: document.querySelector('.side-panel') });

mainHeadroom.init();
sideHeadroom.init();

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


Особенности работы с внутренними прокручиваемыми элементами

При работе с внутренними контейнерами нужно учитывать следующие моменты:

  1. Высота контейнера — если прокручиваемый блок меньше высоты содержимого, логика offset может срабатывать некорректно. Рекомендуется задавать offset с учётом высоты видимой части контейнера.
  2. События touch — для мобильных устройств события touchmove в контейнерах обрабатываются отдельно. Headroom автоматически корректирует обработку, но для сложных интерфейсов может потребоваться дополнительная оптимизация.
  3. Переполнение содержимого — контейнер с overflow: auto или overflow: scroll необходимо использовать как источник прокрутки, а не window, иначе заголовок не будет корректно реагировать.

Синхронизация состояния нескольких заголовков

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

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

  if (scrollTop > 100) {
    mainHeader.classList.add('headroom--unpinned');
    sideHeader.classList.add('headroom--unpinned');
  } else {
    mainHeader.classList.remove('headroom--unpinned');
    sideHeader.classList.remove('headroom--unpinned');
  }
});

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


Производительность при множественных экземплярах

При работе с большим количеством контейнеров важно минимизировать нагрузку на обработчики событий scroll. Рекомендуется:

  • Использовать tolerance для снижения количества вызовов изменений классов.
  • Применять requestAnimationFrame для обновления классов:
container.addEventListener('scroll', () => {
  window.requestAnimationFrame(() => {
    headroom.update();
  });
});
  • Ограничивать количество одновременно активных экземпляров Headroom.js только необходимыми элементами.

Взаимодействие с динамически создаваемыми контейнерами

Если контейнеры добавляются динамически через JavaScript, Headroom.js нужно инициализировать после вставки элемента в DOM:

function createScrollablePanel() {
  const panel = document.createElement('div');
  panel.classList.add('scrollable-container');
  document.body.appendChild(panel);

  const header = panel.querySelector('.header');
  const headroom = new Headroom(header, { scroll: panel });
  headroom.init();
}

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


Множественные области прокрутки в Headroom.js позволяют создавать сложные интерфейсы с независимым поведением заголовков, обеспечивая гибкость и контроль над пользовательским опытом. Правильная инициализация экземпляров для каждого контейнера и оптимизация обработки событий прокрутки являются ключевыми аспектами эффективной реализации.