offsetParent、offsetLeft/offsetTop深度剖析

element.offsetParent

定义

element.offsetParent为包含element的祖先元素中,层级最近的定位元素。 也就是说,offsetParent必须知足三个条件:css

  • 是element的祖先元素
  • 最靠近element
  • 是定位元素,即position属性不为static
<div class="position-outer" style="position: relative;">
    <div class="position" style="postion: relative;">
        <div class="not-position">
        	<div class="box">
        	</div>
        </div>
    </div>
</div>
复制代码

打印box元素的offsetParent:html

因而可知,box祖先元素中存在:

  • 层级为3的定位元素 position-outer
  • 层级为2的定位元素 position-inner
  • 层级为1的非定位元素 not-position

position-inner是同时知足层级最近和定位两个条件的。web

祖先元素中不存在定位元素

<div class="box"></div>
复制代码

webkit内核、Firefox下的特殊状况

  • element自身的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>
复制代码

  • element自身的position属性为fixed
<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 = content + (垂直滚动条的宽度) + padding + borderbash

  • 无滚动条状况下
<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

  • 有滚动条状况下

能够看到,滚动条包含在padding中,所以,offsetWidth与在无滚动条状况下,大小不变。

element.offsetLeft / element.offsetTop

定义

element左上角相对于offsetParent左边界的偏移值。post

有个疑问? element的左上角 与 offsetParent的左边界如何定义?是content-box、padding-box仍是margin-box?spa

<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;
}
复制代码

很明显,box的offsetParent为postion3d

打印box.offsetLeft和box.offsetTop:

在文档流中,box的整个margin-box是在position的content-box中的,由此可猜想:code

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

真的是这样吗?其实并无那么简单,须要分两种状况讨论:htm

element在正常文档流中

element.offsetLeft是指element的border-box左上角相对offsetParent的content-box的偏移量

因为position: relative的元素并无脱离文档流,所以,也须要加入到offseLeft/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,正好是parent的marginLeft、borderLeft 、paddingLeft之和,11 + 12 + 13 = 36,由此获得最终的计算公式:

element.offsetLeft = offsetParent.paddingLeft + element.left + element.marginLeft + (element与element.offsetParent之间全部 在正常文档流且position属性不为relative的元素 marginLeft、borderLeft、paddingLeft之和)

element与element.offsetParent之间存在浮动元素

如今,咱们让parent向右浮动:

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

打印box.offsetLeft和box.offsetTop:

此次只有box.offsetLeft变化了,并且也能够猜想到是因为parent的右浮,box是其子元素,一块儿右浮,致使box.offsetLeft变化的。

这下要怎么计算?难道还要算浮动的距离吗?

并不须要!只要借助parent就能计算!仔细想一想,element与element.offsetParent必定是没有浮动元素的,那么对于parent,其offsetParent也就是box的offsetParent,即postition。

咱们打印下parent.offsetleft:

再计算box到parent之间的偏移量: box.left + box.marginLeft + parent.paddingLeft + parent.borderLeft + parent.marginLeft = 31 + 25 + 11 + 12 + 13 = 92

76 + 92 = 168,与box.offsetLeft一致,这也说明咱们的计算公式是正确的!

element脱离文档流

也就是说element的display属性为absolute或fixed,因为fixed会致使offsetParent为null,因此咱们将box的display设置为absolute:

<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属性为absolute或fixed的元素,是相对于包含块的padding-box定位的,所以在计算offsetLeft时,就不须要考虑offsetParent的paddingLeft了。

而且,element是脱离文档流的,也就是说,除了element.offsetParent,再也不与其它任何元素产生联系,也就不须要再考虑element与element.offsetParent之间的任何元素了。

所以,计算公式很是简单:

element.offsetLeft = element.left + element.marginLeft

相关文章
相关标签/搜索