Автоматическое перепозиционирование

Автоматическое позиционирование календаря в Pikaday строится вокруг задачи корректного отображения всплывающего UI-элемента относительно input-поля с учётом границ viewport, прокрутки контейнеров и доступного пространства. Основная цель механизма — предотвратить обрезание календаря за пределами экрана и обеспечить предсказуемое поведение при изменении размеров окна или скролле страницы.

Pikaday создаёт отдельный DOM-элемент календаря и привязывает его к полю ввода. По умолчанию используется абсолютное позиционирование относительно документа или указанного контейнера. При открытии календаря вычисляются координаты input-элемента через getBoundingClientRect(), после чего рассчитывается начальная точка размещения.

Ключевые параметры, влияющие на позицию:

  • горизонтальное смещение (left)
  • вертикальное смещение (top)
  • высота календаря
  • ширина календаря
  • размеры viewport
  • наличие scroll-контейнеров

После первичного вычисления выполняется проверка на переполнение границ экрана.

Алгоритм автоматического выбора стороны отображения

При стандартной конфигурации Pikaday пытается отобразить календарь под input-полем. Если доступного пространства снизу недостаточно, выполняется переключение вверх.

Логика упрощённо выглядит так:

  1. Определяется высота календаря.
  2. Вычисляется расстояние от input до нижней границы viewport.
  3. Если расстояние меньше высоты календаря — выбирается позиция сверху.
  4. Иначе используется позиция снизу.

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

Особое внимание уделяется случаям, когда input расположен близко к краям экрана — тогда применяется комбинированная корректировка по обеим осям.

Пересчёт позиции при открытии

Каждое открытие календаря инициирует пересчёт координат. Это важно, поскольку DOM может измениться между инициализацией и открытием:

  • изменяется размер окна браузера
  • появляется/исчезает фиксированный header
  • происходит прокрутка страницы
  • меняется масштаб (zoom)

Pikaday вызывает внутреннюю процедуру позиционирования непосредственно в момент onOpen, гарантируя актуальность расчётов.

Важный аспект: позиция не кэшируется, а вычисляется заново при каждом открытии.

Обработка прокрутки и фиксированных контейнеров

При размещении календаря внутри scroll-контейнера возникает дополнительная сложность: координаты input становятся относительными к текущему состоянию прокрутки.

Для корректной работы учитываются:

  • scrollTop и scrollLeft родительских элементов
  • offset-контекст контейнера
  • возможное использование position: fixed

Если календарь привязан к document.body, он ведёт себя как overlay-элемент и реагирует на глобальные координаты viewport. При привязке к кастомному контейнеру расчёт смещается в локальную систему координат.

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

Pikaday не ограничивается статическим вычислением позиции при открытии. В типичных конфигурациях реализуется пересчёт при изменении размеров окна браузера.

При событии resize выполняется:

  • повторное вычисление bounding box input
  • повторная проверка доступного пространства
  • корректировка координат календаря

Это предотвращает ситуацию, когда календарь «уезжает» за пределы экрана после изменения ориентации устройства или изменения размеров окна.

Внутренний механизм корректировки (flip-логика)

Flip-логика является основным элементом автоматического позиционирования. Она отвечает за переключение календаря между верхним и нижним отображением.

Условно поведение можно описать так:

  • Default state: календарь отображается снизу input
  • Overflow bottom: переключение вверх
  • Overflow top (редкий случай): возврат вниз с дополнительным смещением
  • Horizontal overflow: сдвиг влево относительно input

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

Работа с CSS-классами состояния

При автоматическом перепозиционировании Pikaday использует CSS-классы, отражающие текущее положение календаря. Это позволяет стилизовать разные сценарии отображения.

Часто используются состояния:

  • отображение снизу
  • отображение сверху
  • смещение влево/вправо
  • активное состояние открытия

CSS-классы позволяют компенсировать визуальные проблемы, возникающие при изменении позиции, например изменение стрелки-указателя календаря.

Влияние параметра container

Параметр container влияет на систему координат, в которой выполняется расчёт позиции. При его использовании календарь:

  • рендерится внутри указанного DOM-элемента
  • рассчитывает координаты относительно контейнера
  • учитывает scroll этого контейнера, а не документа

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

В таких случаях автоматическое позиционирование становится более сложным, так как границы ограничены не viewport, а внутренним контейнером.

Поведение при динамическом изменении размеров календаря

Размер календаря Pikaday зависит от:

  • количества недель в месяце
  • включённого отображения соседних месяцев
  • наличия заголовков и навигации

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

Особенности мобильных браузеров

На мобильных устройствах автоматическое позиционирование сталкивается с дополнительными ограничениями:

  • динамическая высота viewport из-за адресной строки
  • виртуальная клавиатура, перекрывающая часть экрана
  • изменение ориентации устройства

В этих условиях Pikaday ориентируется на актуальные размеры window.innerHeight, а не на статические значения viewport, что позволяет адаптировать позицию календаря под реальные доступные границы.

Конфликты с transform и overflow

Автоматическое позиционирование может давать некорректные результаты при наличии CSS-свойств:

  • transform у родительских элементов
  • overflow: hidden на контейнерах
  • position: relative с нестандартными контекстами наложения

В таких случаях координатная система может смещаться, и Pikaday компенсирует это через пересчёт offset-значений и переход к body-контексту.

Повторное позиционирование через API

Некоторые сценарии требуют ручного вызова пересчёта позиции. Для этого используется метод adjustPosition() (или аналогичные внутренние механизмы библиотеки в зависимости от версии).

Он выполняет:

  • повторное вычисление bounding rect
  • проверку доступного пространства
  • применение flip-логики
  • обновление inline-стилей calendar element

Это полезно при динамическом изменении layout, например при раскрытии сайдбаров или модальных окон поверх календаря.

Синхронизация с анимацией отображения

В случаях, когда календарь отображается с анимацией (fade/scale), позиционирование должно происходить до начала анимации. Иначе возможны визуальные скачки.

Поэтому порядок операций обычно следующий:

  1. вычисление позиции
  2. установка координат
  3. применение класса открытия
  4. запуск анимации

Нарушение этого порядка приводит к эффекту «перепрыгивания» календаря при открытии.

Приоритеты при конфликте условий

Если одновременно выполняется несколько условий переполнения (например, нет места ни сверху, ни снизу), Pikaday выбирает стратегию минимального смещения:

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

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