前言
偏移量offset是JavaScript中非常重要的一个概念,涉及偏移量的主要属性有:offsetLeft、offsetTop、offsetWidth、offsetHeight。当然,还有一个参照属性---定位父级offsetParent。本文将详细介绍这些内容。
当前元素与定位父级的关系图:
定位父级offsetParent
在理解偏移大小之前,首先要理解的就是定位父级offsetParent,之所以翻译成定位父级,那是因为它跟定位有关系。
定位父级offsetParent的定义:“离”当前元素“最近”的 经过定位的(position不等于static)的父级元素。也就是说,它是一个有position属性的父级元素,当前元素是它的子元素。我们知道,元素查找是逐级向上查找的。
<div id="test" >
<div id="test1" style="position: relative">
<div id="test2"></div>
</div>
</div>
此例#test2的定位父级是#test1,在这个例子中,#test1是唯一的一个有position属性的,所以只有它离#test2最近。
<div id="test" style="position: relative;">
<div id="test1" style="position: relative;">
<div id="test2"></div>
</div>
</div>
在此例中,#test2的定位父级依然是#test1,尽管#test和#test1都有position属性,但#test1离#test2最近。
<div id="test" style="position: relative;">
<div id="test1">
<div id="test2"></div>
</div>
</div>
在这个例子中,#test2的定位父级是#test,因为#test有position属性且离#test2最近。
元素自身有fixed定位时,offsetParent返回null。
当元素自身是固定定位时,固定定位是相对于视口定位的,此时没有父级定位,offsetParent返回null。
<!docutype html>
<html>
<head>
<meta charset="utf-8">
<title>深入理解偏移量offset</title>
<style>
</style>
</head>
<body>
<div id="test">
<div id="test1" style="position: relative;">
<div id="test2" style="position: fixed;"></div>
</div>
</div>
<script>
var test2 = document.getElementById("test2");
console.log(test2.offsetParent); //null
</script>
</body>
</html>
元素自身无fixed定位,且父级元素未经过定位,offsetParent返回<body>
<!docutype html>
<html>
<head>
<meta charset="utf-8">
<title>深入理解偏移量offset</title>
<style>
</style>
</head>
<body>
<div id="test">
<div id="test1">
<div id="test2"></div>
</div>
</div>
<script>
var test2 = document.getElementById("test2");
console.log(test2.offsetParent); //<body></body>
</script>
</body>
</html>
元素自身无fixed定位,且父级元素存在经过定位的元素,offsetParent返回 离自身元素最近的且经过定位的父级元素。
<!docutype html>
<html>
<head>
<meta charset="utf-8">
<title>深入理解偏移量offset</title>
<style>
</style>
</head>
<body>
<div id="test" style="position: relative">
<div id="test1" style="position: relative">
<div id="test2"></div>
</div>
</div>
<script>
var test2 = document.getElementById("test2");
console.log(test2.offsetParent); //<div id="test1"></div>
</script>
</body>
</html>
<body>的offsetParent返回null
console.log(document.body.offsetParent); //null
偏移量
偏移量包含offsetLeft、offsetTop、offsetWidth、offsetHeight这四个属性。
offsetWidth
该属性表示元素在水平方向占用的空间大小。无单位(以像素计)。
offsetWidth = border-left-width + padding-left + width + padding-right + border-right-width
offsetHeight
该属性表示元素在垂直方向占用的空间大小。无单位(以像素计)。
offsetHeight = border-top-height + padding-top + height+ padding-top + border-top-height
offsetWidth和offsetHeight在页面中的计算:
<!docutype html>
<html>
<head>
<meta charset="utf-8">
<title>深入理解偏移量offset</title>
<style>
</style>
</head>
<body>
<div id="test" style="position: relative">
<div id="test1" style="position: relative">
<div id="test2" style="width: 100; height: 100; margin: 10; padding: 10; border: 1px solid red"></div>
</div>
</div>
<script>
var test2 = document.getElementById("test2");
//122 = 10 + 10 + 100 +2
console.log(test2.offsetWidth); //122
//122 = 10 + 10 + 100 +2
console.log(test2.offsetHeight); //122
</script>
</body>
</html>
注意:如果存在滚动条,offsetWidth也包括垂直滚动条的宽度,offsetHeight也包括水平滚动条的高度。
offsetTop
offsetTop表示元素的上外边框与offsetParent上内边框之间的像素距离。
offsetLeft
offsetLeft表示元素的左外边框与offsetParent左内边框之间的像素距离。
<!docutype html>
<html>
<head>
<meta charset="utf-8">
<title>深入理解偏移量offset</title>
<style>
</style>
</head>
<body>
<div id="test1" style="position: relative;width: 200; height: 200; margin: 10; padding: 10; border: 1px solid red ">
<div id="test2" style="width: 100; height: 100; margin: 10; padding: 10; border: 1px solid red"></div>
</div>
<script>
var test2 = document.getElementById("test2");
//20 = test2.marginTop(10) + test1.paddingTop(10)
console.log(test2.offsetTop); //20
//20 = test2.marginLeft(10) + test2.marginLeft(10)
console.log(test2.offsetLeft); //20
</script>
</body>
</html>
注意事项
每个偏移量都只是可读的。也就是说不能通过赋值来修改偏移量。
<!docutype html>
<html>
<head>
<meta charset="utf-8">
<title>深入理解偏移量offset</title>
<style>
</style>
</head>
<body>
<div id="test1" style="position: relative;width: 200; height: 200; margin: 10; padding: 10; border: 1px solid red ">
<div id="test2" style="width: 100; height: 100; margin: 10; padding: 10; border: 1px solid red"></div>
</div>
<script>
var test2 = document.getElementById("test2");
//20 = test2.marginTop(10) + test1.paddingTop(10)
console.log(test2.offsetTop); //20
test2.offsetTop = 30;//尝试将偏移量修改为30
console.log(test2.offsetTop); //20 只是可读的,不能修改。
//20 = test2.marginLeft(10) + test2.marginLeft(10)
console.log(test2.offsetLeft); //20
</script>
</body>
</html>
上述例子中,想通过赋值运算来修改偏移量,结果是不能修改的,只是可读的。
如果给元素设置了dispaly: none;那么这个元素的偏移量为0。
<!docutype html>
<html>
<head>
<meta charset="utf-8">
<title>深入理解偏移量offset</title>
<style>
</style>
</head>
<body>
<div id="test1" style="position: relative;width: 200; height: 200; margin: 10; padding: 10; border: 1px solid red ">
<div id="test2" style="display: none; width: 100; height: 100; margin: 10; padding: 10; border: 1px solid red"></div>
</div>
<script>
var test2 = document.getElementById("test2");
//20 = test2.marginTop(10) + test1.paddingTop(10)
console.log(test2.offsetTop); //0
test2.offsetTop = 30;//尝试将偏移量修改为30
console.log(test2.offsetTop); //0 只是可读的,不能修改。
//20 = test2.marginLeft(10) + test2.marginLeft(10)
console.log(test2.offsetLeft); //0
</script>
</body>
</html>
每次访问偏移量,都需要重新计算,这是一个很耗性能的工作,所以要尽量重复访问这些偏移量。如果需要访问它们,将它们保存在变量中。