目录
偏移量(offset dimension)是javascript中的一个重要的概念。涉及到偏移量的主要是offsetLeft、offsetTop、offsetHeight、offsetWidth这四个属性。当然,还有一个偏移参照——定位父级offsetParent。本文将详细介绍该部分内容。
一、offset 概述
offset
翻译过来就是偏移量, 我们使用 offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
-
获得元素距离带有定位父元素的位置
-
获得元素自身的大小(宽度高度)
注意:返回的数值都不带单位
♠ offset 系列常用属性 ♠
以上五个偏移量属性,它们都是只读属性。如果元素设置了display:none,则它的偏移量属性均为0。每次访问偏移量属性都需要重新计算,重复访问偏移量属性需耗费大量性能,如需重复访问,应将其值保存在变量中,以提高性能。
参考分析图
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.father {
margin: 100px;
width: 200px;
height: 200px;
background-color: pink;
}
.son {
margin-left: 30px;
width: 100px;
height: 100px;
background-color: purple;
}
.box {
margin: 0 100px;
width: 200px;
height: 200px;
padding: 20px;
background-color: skyblue;
border: 10px solid red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<div class="box"></div>
<script>
// offset 系列
let father = document.querySelector(".father");
let son = document.querySelector(".son");
// 1. offsetParent返回带有定位的父亲,否则返回的是body
console.log(son.offsetParent); // 返回<body>...</body>
// 注意:offsetParent与parentNode的值不一定相等
// 返回最近一级的父亲(亲爸爸) 不管父亲有没有定位
console.log(son.parentNode); // 返回<div class="father">...</div>
// 2. 可以得到元素的偏移量(位置),返回的是不带单位的数值
console.log(father.offsetTop); // 100 ,因为css为其设置的margin为100
console.log(father.offsetLeft); // 100 ,因为css为其设置的margin为100
// 它以带有定位的父亲为准,如果没有父亲或者父亲没有定位 则以 body 为准
console.log(son.offsetLeft); // 130 ,因为虽然其有父亲,但是其父亲没有定位,所以以body为准,即100+30=130
// 3. 可以得到元素的大小(宽度和高度),是包含padding + border + width/height的,不包括margin
let box = document.querySelector(".box");
console.log(box.offsetWidth); // 260
console.log(box.offsetHeight); // 260
</script>
</body>
</html>
下面我们把offset的5个偏移属性,分别一一介绍一下
定位父级
offsetParent
offsetParent属性是一个偏移参照,翻译为定位父级,即当前元素最近的有定位的父级元素(position不等于static)。定位父级分为下列四种情况。
在理解偏移大小之前,首先要理解offsetParent。人们并没有把offsetParent翻译为偏移父级,而是翻译成定位父级,很大原因是offsetParent与定位有关。
(1)当前元素自身有fixed定位,offsetParent返回null
当元素自身有fixed固定定位时,我们知道固定定位的元素相对于视口进行定位,此时没有定位父级,offsetParent的结果为null。
注意:firefox浏览器有兼容性问题——firefox没有考虑固定定位问题,返回body元素
<!-- 元素自身有fixed定位,offsetParent的结果为null -->
<div id="box" style="position:fixed;"></div>
<script>
let box = document.querySelector('#box');
console.log(box.offsetParent); // null
//兼容问题:firefox浏览器没有考虑固定定位的问题,返回body元素,其他浏览器都返回null
</script>
(2)当前元素自身无fixed定位,且不存在有定位的父级元素,offsetParent返回body元素
<!-- 元素自身无fixed定位,且父级元素都未经过定位,offsetParent的结果为<body> -->
<div>
<span id="box"></span>
</div>
<script>
let box = document.querySelector('#box');
console.log(box.offsetParent); // <body>...</boby>
</script>
(3)当前元素自身无fixed定位,且存在有定位的父级元素,offsetParent返回最近的有定位的父级元素
<!--元素自身无fixed定位,且父级元素存在经过定位的元素,offsetParent的结果为离自身元素最近的经过定位的父级元素-->
<div id="div0" style="position:absolute;">
<div id="div1" style="position:absolute;">
<span id="box"></span>
</div>
</div>
<script>
let box = document.querySelector('#box');
console.log(span.offsetParent); // <div id="div1" style="position:absolute;">...</div>
</script>
(4)body元素无父元素节点,offsetParent返回null
<!-- <body>元素的parentNode是null -->
<script>
console.log(document.body.offsetParent); // null
</script>
★ IE7 浏览器Bug
对于定位父级offsetParent来说,IE7-浏览器存在以下bug
【bug1】当元素本身经过绝对定位或相对定位,且父级元素无定位时,IE7-浏览器下offsetParent返回的结果是<html>
<div id="test" style="position:absolute;"></div>
<script>
//IE7-浏览器返回<html>,其他浏览器返回<body>
let box = document.querySelector('#test');
console.log(box.offsetParent);
</script>
<div id="test" style="position:relative;"></div>
<script>
//IE7-浏览器返回<html>,其他浏览器返回<body>
let box = document.querySelector('#test');
console.log(box.offsetParent);
</script>
<div id="test" style="position:fixed;"></div>
<script>
// firefox并没有考虑固定定位的问题,返回<body>,其他浏览器都返回null
let box = document.querySelector('#test');
console.log(box.offsetParent);
</script>
【bug2】如果父级元素存在触发haslayout的元素或有定位的元素,则offsetParent的结果为离自身元素最近的有定位或触发haslayout的父级元素
注意:关于haslayout的详细信息:haslayout详解 - 小火柴的蓝色理想 - 博客园
<div id="div0" style="display:inline-block;">
<div id='test'></div>
</div>
<script>
let box = document.querySelector('#test');
//IE7-浏览器返回<div id="div0">,其他浏览器返回<body>
console.log(box.offsetParent);
</script>
<div id="div0" style="position:absolute;">
<div id="div1" style="display:inline-block;">
<div id='test'></div>
</div>
</div>
<script>
let box = document.querySelector('#test');
//IE7-浏览器返回<div id="div1">,其他浏览器返回<div id="div0">
console.log(box.offsetParent);
</script>
<div id="div0" style="display:inline-block;">
<div id="div1" style="position:absolute;">
<div id='test'></div>
</div>
</div>
<script>
let box = document.querySelector('#test');
//所有浏览器都返回<div id="div1">
console.log(box.offsetParent);
</script>