Глубинный анализ offsetParent, offsetLeft/offsetTop

DOM

element.offsetParent

определение

element.offsetParent — это ближайший позиционированный элемент в элементе-предке, содержащем element. То есть offsetParent должен удовлетворять трем условиям:

  • является предком элемента element
  • ближайший к элементу
  • Является элементом позиционирования, то есть атрибут position не является статическим
<div class="position-outer" style="position: relative;">
    <div class="position" style="postion: relative;">
        <div class="not-position">
        	<div class="box">
        	</div>
        </div>
    </div>
</div>

Напечатайте offsetParent элемента box:

Видно, что элемент-предок box существует:

  • Уровень 3 - это элемент позиционирования.
  • Позиционирование элемента position-inner на уровне 2
  • Непозиционированный элемент на уровне 1 не-позиции

position-inner удовлетворяет двум условиям ближайшего уровня и позиционирования одновременно.

Позиционируемый элемент не существует в элементе-предке

<div class="box"></div>

Особые случаи в ядре webkit и Firefox

  • Свойство display самого элемента равно none
<div class="position-outer" style="position: relative;">
    <div class="position" style="postion: relative;">
        <div class="not-position">
        	<div class="box" style="display: none;"> <!-- 注意这里! -->
        	</div>
        </div>
    </div>
</div>

  • Свойство позиции самого элемента фиксировано
<div class="position-outer" style="position: relative;">
    <div class="position" style="postion: relative;">
        <div class="not-position">
        	<div class="box" style="position: fixed;"> <!-- 注意这里! -->
        	</div>
        </div>
    </div>
</div>

element.offsetWidth / element.offsetHeight

определение

offsetWidth = содержимое + (ширина вертикальной полосы прокрутки) + отступ + граница

  • Без полосы прокрутки
<div class="box" style="">
</div>
.box {
    width: 200px;
    height: 100px;
    padding: 20px;
    border: 12px solid red;
    margin: 25px;
}

печать element.offsetWidth:

offsetWidth = 200(content) + 20 * 2(padding) + 12 * 2(border) = 264

  • С полосой прокрутки

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

element.offsetLeft / element.offsetTop

определение

Значение смещения верхнего левого угла элемента относительно левого края offsetParent.

Есть вопрос? Как определить верхний левый угол элемента и левую границу offsetParent? Это поле содержимого, поле заполнения или поле поля?

<div class="position">
    <div class="box">
    </div>
</div>
.position {
    position: relative;
    top:  0;
    left:  0;
    width: 400px;
    height: 200px;
    padding:  35px;
    border: 15px solid purple;
}

.box {
    width: 200px;
    height: 100px;
    padding: 20px;
    border:  12px solid red;
    margin:  25px;
}

Очевидно, что offsetParent поля - это position

Распечатайте box.offsetLeft и box.offsetTop:

В потоке документов все поле поля поля находится в поле содержимого позиции, поэтому можно предположить, что:

box.offsetLeft = position.paddingLeft + box.marginleft = 35 + 25 = 60

Это действительно так? На самом деле все не так просто, о нем нужно говорить в двух случаях:

Элемент в нормальном потоке документов

element.offsetLeft относится к верхнему левому углу элемента рамки блока содержимого offsetParent напротив смещения

Так как элемент с position:relative не отделяется от документооборота, его тоже нужно добавить в расчет offsetLeft/offsetTop

Измените свойство box css:

.box {
    position: relative; /* 新增的 */
    top: 31px;          /* 新增的 */
    left: 31px;         /* 新增的 */
    width: 200px;
    height: 100px;
    padding: 20px;
    border:  12px solid red;
    margin:  25px;
}

Снова напечатайте box.offsetLeft и box.offsetTop:

Значения обоих увеличиваются на 31, что является значением, соответствующим свойствам top и left, тем самым обновляя формулу расчета:

element.offsetLeft = offsetParent.paddingLeft + element.left + element.marginLeft

Однако все вышеперечисленное вычисляется в самом простом случае, то есть между element и element.offsetParent нет других уровней элементов!

Вставляем еще один элемент между element и element.offsetParent:

<div class="position">
    <div class="middle">    <!-- 新增的 -->
        <div class="box">
        </div>
    </div>
</div>
.parent {
    width: 30px;
    height: 150px;
    padding:  11px;
    border:  12px solid pink;
    margin-left:  13px;
}

Распечатайте box.offsetLeft и box.offsetTop:

Ценности обоих снова изменились! По сравнению с прошлым разом он увеличился на 36, что в точности равно сумме marginLeft, borderLeft и paddingLeft родителя, 11 + 12 + 13 = 36, таким образом, получается окончательная формула расчета:

element.offsetLeft = offsetParent.paddingLeft + element.left + element.marginLeft + (сумма marginLeft, borderLeft, paddingLeft всех элементов между element и element.offsetParent, которые находятся в обычном потоке документа и чей атрибут position не является относительным)

Между element и element.offsetParent есть плавающий элемент.

Теперь давайте переместим родителя вправо:

.parent {
    float: right;
    width: 30px;
    height: 150px;
    padding:  11px;
    border:  12px solid pink;
    margin-left:  13px;
}

Распечатайте box.offsetLeft и box.offsetTop:

На этот раз изменился только box.offsetLeft, и также можно догадаться, что это происходит из-за того, что родитель смещается вправо, box является его дочерним элементом, а смещение вправо приводит к изменению box.offsetLeft.

Как рассчитать теперь? Это считается плавающим расстоянием?

Это не нужно! Пока вы используете родителя для расчета! Подумайте об этом внимательно, element и element.offsetParent не должны иметь плавающих элементов, тогда для родителя его offsetParent также является offsetParent поля, то есть положением.

Мы печатаем parent.offsetleft:

Затем вычислите смещение между блоком и родителем: box.left + box.marginLeft + parent.paddingLeft + parent.borderLeft + parent.marginLeft = 31 + 25 + 11 + 12 + 13 = 92

76 + 92 = 168, что согласуется с box.offsetLeft, что также показывает, что наша формула расчета верна!

элемент покидает документооборот

Другими словами, свойство отображения элемента является абсолютным или фиксированным.Поскольку фиксированное приведет к тому, что offsetParent будет равен нулю, мы устанавливаем отображение поля в абсолютное:

<div class="position">
    <div class="box">
    </div>
</div>
.box {
    position: absolute; /* 新增的 */
    top: 31px;
    left:  31px;
    width: 200px;
    height: 100px;
    padding: 20px;
    border:  12px solid red;
    margin:  25px;
}

.position {
    position: relative;
    top:  0;
    left:  0;
    width: 400px;
    height: 200px;
    padding:  35px;
    border: 15px solid purple;
}

Распечатайте box.offsetLeft и box.offsetTop:

Мы знаем, что элемент, чей атрибут display является абсолютным или фиксированным, позиционируется относительно поля заполнения содержащего его блока, поэтому при вычислении offsetLeft не нужно учитывать paddingLeft offsetParent.

Более того, элемент находится вне потока документов, то есть, кроме element.offsetParent, он больше не связан ни с каким другим элементом, и нет необходимости рассматривать какой-либо элемент между element и element.offsetParent.

Поэтому формула расчета очень проста:

element.offsetLeft = element.left + element.marginLeft