getClippingRect

Внутренний механизм библиотеки Floating UI опирается на точные вычисления видимой области, в пределах которой должен отображаться плавающий элемент (tooltip, dropdown, popover). Ключевую роль в этом процессе играет функция getClippingRect, отвечающая за определение прямоугольника отсечения (clipping rectangle).

Этот прямоугольник описывает область, внутри которой элемент считается видимым. Всё, что выходит за его границы, потенциально может быть скрыто из-за CSS-свойств вроде overflow, а также из-за ограничений окна просмотра (viewport).


Что такое clipping rectangle

Clipping rectangle — это итоговая область, полученная в результате пересечения нескольких ограничивающих контейнеров:

  • viewport (область видимости браузера)
  • scroll-контейнеры
  • элементы с overflow: hidden | auto | scroll
  • корневой документ (documentElement)

Именно эта область определяет, где плавающий элемент может находиться без обрезания.


Основные задачи getClippingRect

Функция выполняет несколько важных действий:

  1. Собирает список clipping-предков (clipping ancestors)
  2. Вычисляет bounding rect каждого из них
  3. Пересекает эти прямоугольники
  4. Возвращает итоговый ограничивающий прямоугольник

Источники ограничений

1. Viewport

Базовое ограничение — это текущая область окна браузера:

  • ширина и высота окна
  • текущая прокрутка
  • zoom (учитывается через layout viewport)

2. Clipping ancestors

Это предки элемента, которые могут обрезать содержимое:

  • элементы с overflowvisible
  • контейнеры с transform (создают новый контекст)
  • fixed/absolute контексты позиционирования

3. Root boundary

Может быть:

  • viewport
  • document
  • кастомный контейнер

Алгоритм работы

Шаг 1: Получение списка clipping ancestors

Функция определяет все родительские элементы, которые могут ограничивать видимость:

getClippingAncestors(element)

В список включаются:

  • scrollable контейнеры
  • элементы с overflow
  • корневые контейнеры

Шаг 2: Получение прямоугольников

Для каждого предка вычисляется его bounding rectangle:

getBoundingClientRect(element)

Также учитываются:

  • скролл
  • border-box
  • трансформации

Шаг 3: Пересечение прямоугольников

Все прямоугольники пересекаются между собой:

intersectionRect = intersectRects(rect1, rect2)

Итеративно:

(((viewport ∩ ancestor1) ∩ ancestor2) ∩ ancestor3) ...

Шаг 4: Возврат итогового rect

Результат имеет структуру:

{
  x: number,
  y: number,
  width: number,
  height: number
}

Этот rect используется другими частями системы позиционирования.


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

getClippingRect активно используется в middleware:

detectOverflow

  • определяет, выходит ли элемент за границы
  • сравнивает позицию floating элемента с clipping rect

shift

  • сдвигает элемент внутрь допустимой области

flip

  • меняет сторону размещения при нехватке места

Пример логики использования

const clippingRect = getClippingRect({
  element,
  boundary,
  rootBoundary,
  strategy
});

Где:

  • element — целевой элемент
  • boundary — список границ (например, "clippingAncestors")
  • rootBoundary"viewport" или "document"
  • strategy"absolute" или "fixed"

Влияние стратегии позиционирования

absolute

  • зависит от ближайшего позиционированного родителя
  • clipping ancestors играют ключевую роль

fixed

  • привязан к viewport
  • игнорирует часть scroll-контейнеров
  • clipping рассчитывается иначе

Особенности вычислений

Учет скролла

Все координаты нормализуются с учетом прокрутки:

  • scrollX / scrollY
  • offsetParent

Поддержка iframe

Если элемент находится внутри iframe:

  • clipping учитывает границы iframe
  • координаты пересчитываются относительно окна

CSS transform

Элементы с transform:

  • создают новый containing block
  • влияют на вычисление clipping ancestors

Оптимизации

getClippingRect оптимизирована для:

  • минимизации количества DOM-запросов
  • кэширования промежуточных значений
  • работы без лишних reflow

Частые проблемы

1. Неожиданное обрезание

Причина:

overflow: hidden;

на родительском элементе


2. Некорректное позиционирование при scroll

Связано с:

  • неправильной стратегией (absolute vs fixed)
  • вложенными scroll-контейнерами

3. Popover “обрезается” внутри контейнера

Решение:

  • использовать boundary: 'viewport'
  • или изменить структуру DOM

Практическое значение

getClippingRect является фундаментом для:

  • адаптивного позиционирования
  • предотвращения выхода за границы экрана
  • корректной работы UI-компонентов в сложных layout’ах

Без точного определения clipping области невозможно реализовать:

  • корректный flip
  • плавный shift
  • точный detectOverflow

Связанные функции

  • getBoundingClientRect
  • getClippingAncestors
  • detectOverflow
  • computePosition

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


Итоговая роль в архитектуре

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