Поиск в DOM ближайшего родителя с position: relative

Вы когда-нибудь сталкивались с дилеммой позиционирования CSS, когда элемент с position: absolute позиционируется не так, как вы ожидали? Установка абсолютного позиционирования для элемента позиционирует его относительно его ближайшего предка, для которого задано относительное положение.

На этом изображении элемент с абсолютным позиционированием в обоих случаях позиционируется с помощью одного и того же CSS:

.absolute {
  position: absolute;
  top: 100%;
  left: 0;
}

Однако, при этом он оказывается в разных местах. Это связано с тем, что в первом примере его родительский элемент (розовый элемент) имеет position: relative, а для второго предок с относительным позиционированием другой (серый элемент).

See this code Relative and absolute positioning on x.xhtml.ru.

Стоит отметить, в случае, когда относительное позиционирование отсутствует у всех предков, элемент с position: absolute будет располагаться относительно <body>.

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

Исследование всего кода может занять много времени, но есть простой способ найти ближайшего расположенного родителя в Javascript, который можно применить прямо в консоли браузера.

Если открыть вкладку «Консоль» в инструментах разработчика В Chrome и Firefox, ссылку на текущий выбранный элемент можно получить, набрав $0. Затем, чтобы найти ближайшего предка этого элемента, у которого значение position установлено не по умолчанию (static), можно использовать свойство объекта offsetParent. Попробуйте выбрать элемент и набрать в консоли:

$0.offsetParent

На самом деле это ещё не сообщает ничего о позиционировании элемента. Чтобы узнать значение свойства position элемента, можно использовать метод getComputedStyle():

getComputedStyle($0.offsetParent).position

Набрав в консоли $_, можно получить последнее вычисленное выражение, как переменную, так выражение:

$0.offsetParent

показывает элемент. Затем:

getComputedStyle($_).position

возвращает значение свойства position. Если позиционирование этого элемента отличается от relative, можно сделать то же самое снова и продолжать движение вверх по дереву DOM, пока не найдется предок, относительно которого позиционируется выбранный элемент. Еще можно написать рекурсивную функцию и перебирать элементы, пока не найдется элемент с нужным позиционированием. Есть несколько предостережений: offsetParent вернет null, если для элемента установлено position: fixed, либо у него или его родителя display: none.

P.S.: В оригинале автор не осилил написать рекурсию для поиска первого из предков с position: relative. Она может выглядеть как-то так:

let el = $0.offsetParent
while (el && getComputedStyle(el).position !== 'relative') {
  el = el.offsetParent
}