Параметр scrollEl для контейнеров

Параметр scrollEl в библиотеке Stickybits определяет пользовательский контейнер прокрутки, внутри которого должен отслеживаться скролл для «прилипающего» элемента. По умолчанию библиотека ориентируется на глобальный объект window, однако в современных интерфейсах часто используются вложенные скролл-контейнеры (overflow: auto или overflow: scroll), и в таких случаях стандартное поведение оказывается недостаточным.

Использование scrollEl позволяет:

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

Базовый синтаксис

stickybits('.element', {
  scrollEl: '.scroll-container'
});

В качестве значения может передаваться:

  • CSS-селектор
  • DOM-элемент

Пример с DOM-элементом:

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

stickybits('.element', {
  scrollEl: container
});

Принцип работы

При указании scrollEl библиотека:

  1. Назначает обработчик события scroll не на window, а на указанный контейнер.

  2. Рассчитывает позиции относительно границ этого контейнера.

  3. Определяет моменты перехода между состояниями:

    • обычное положение (default)
    • прилипание (sticky)
    • выход за пределы (stuck)

Ключевой момент — координаты элемента вычисляются в системе координат контейнера, а не документа.


Когда необходим scrollEl

1. Вложенные прокручиваемые блоки

.scroll-container {
  height: 400px;
  overflow-y: auto;
}
<div class="scroll-container">
  <div class="sidebar">...</div>
</div>

Без scrollEl:

  • Stickybits отслеживает прокрутку окна
  • элемент не «прилипает», так как контейнер прокручивается независимо

С scrollEl:

stickybits('.sidebar', {
  scrollEl: '.scroll-container'
});

2. Модальные окна

Модальные окна часто блокируют прокрутку страницы (body { overflow: hidden }), создавая собственный scroll-контейнер.

stickybits('.modal-header', {
  scrollEl: '.modal-body'
});

3. Сложные layout-системы

В интерфейсах с несколькими колонками и независимыми областями прокрутки:

  • левая панель — отдельный scroll
  • центральный контент — другой scroll

Каждому sticky-элементу требуется свой scrollEl.


Влияние на расчёт границ

Stickybits вычисляет:

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

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

  • offsetTop элемента берётся относительно контейнера
  • высота контейнера учитывается как ограничение
  • событие scroll привязано к контейнеру

Это предотвращает типичные ошибки:

  • преждевременное «прилипание»
  • некорректный выход из sticky-состояния
  • дергание элемента

Взаимодействие с CSS

Для корректной работы необходимо:

Контейнер

.scroll-container {
  position: relative;
  overflow-y: auto;
}

Sticky-элемент

.element {
  position: relative;
}

Stickybits сам добавляет классы:

  • .js-is-sticky
  • .js-is-stuck

Ограничения и особенности

1. Контейнер должен реально прокручиваться

Если высота контейнера меньше содержимого и прокрутки нет — scrollEl не даст эффекта.

2. Вложенные scroll-контейнеры

Если контейнеры вложены:

<div class="outer">
  <div class="inner">
    <div class="element"></div>
  </div>
</div>

Нужно выбирать именно тот контейнер, который:

  • реально обрабатывает прокрутку
  • имеет overflow

Ошибка выбора приводит к:

  • отсутствию реакции
  • неправильным координатам

Работа с несколькими элементами

stickybits('.item', {
  scrollEl: '.scroll-container'
});

Stickybits создаёт независимые экземпляры для каждого элемента, но использует один scroll-контейнер.

Оптимизация:

  • обработчик scroll не дублируется
  • вычисления выполняются централизованно

Динамическое изменение контейнера

В случае изменения DOM:

const instance = stickybits('.element', {
  scrollEl: '.container-1'
});

// позже
instance.cleanup();

stickybits('.element', {
  scrollEl: '.container-2'
});

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


Производительность

Использование scrollEl влияет на производительность следующим образом:

Плюсы:

  • уменьшается количество глобальных обработчиков
  • локализуется область вычислений

Минусы:

  • при большом количестве контейнеров — рост числа слушателей
  • частые scroll-события внутри контейнера могут вызывать перерасчёты

Рекомендации:

  • минимизировать количество scroll-контейнеров
  • избегать глубоких вложенностей
  • использовать throttle/debounce при необходимости (в пользовательской логике)

Типичные ошибки

Неверный селектор

scrollEl: '.container' // элемент не найден

Результат:

  • fallback на window
  • некорректное поведение

Контейнер без overflow

.container {
  overflow: visible;
}

Stickybits не получает scroll-событий.


Использование position: sticky вместе с Stickybits

Stickybits может работать как полифилл, но при использовании scrollEl:

  • браузерный position: sticky не учитывает кастомный контейнер
  • возникает рассинхронизация

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

.element {
  position: relative;
}

Расширенные сценарии

Sticky внутри горизонтального скролла

stickybits('.element', {
  scrollEl: '.horizontal-scroll'
});

Stickybits отслеживает только вертикальный скролл, но контейнер может быть горизонтальным — важно учитывать направление прокрутки.


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

stickybits('.element', {
  scrollEl: '.container',
  stickyBitStickyOffset: 20
});

Offset применяется относительно контейнера, а не окна.


Внутренние механизмы

При инициализации с scrollEl:

  • определяется bounding box контейнера
  • сохраняется ссылка на scroll-родителя
  • подписка на scroll и resize
  • вычисление scrollTop контейнера вместо window.pageYOffset

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


Практический пример

<div class="panel">
  <div class="panel-content">
    <div class="sticky">Навигация</div>
    <div class="long-content">...</div>
  </div>
</div>
.panel-content {
  height: 300px;
  overflow-y: auto;
}
stickybits('.sticky', {
  scrollEl: '.panel-content'
});

Результат:

  • элемент «прилипает» внутри панели
  • не зависит от прокрутки всей страницы
  • корректно ограничен высотой контейнера

Поведение при вложенности и границах

Stickybits учитывает:

  • верхнюю границу контейнера → момент входа в sticky
  • нижнюю границу → момент выхода (stuck)

При scrollEl:

  • границы вычисляются строго внутри контейнера
  • внешний документ не влияет на поведение

Это критично для:

  • SPA-приложений
  • dashboard-интерфейсов
  • редакторов и IDE в браузере