javascript好文---深入理解定位父级offsetParent及偏移大小
前面的话
偏移量(offset dimension)是javascript中的一个重要的概念。涉及到偏移量的主要是offsetLeft、offsetTop、offsetHeight、offsetWidth这四个属性。当然,还有一个偏移参照——定位父级offsetParent。本文将详细介绍该部分内容

offsetParent定位父级
在理解偏移大小之前,首先要理解offsetParent。人们并没有把offsetParent翻译为偏移父级,而是翻译成定位父级,很大原因是offsetParent与定位有关
定位父级offsetParent的定义是:与当前元素最近的经过定位(position不等于static)的父级元素,主要分为下列几种情况 :
【1】元素自身有fixed定位,offsetParent的结果为null
当元素自身有fixed固定定位时,我们知道固定定位的元素相对于视口进行定位,此时没有定位父级,offsetParent的结果为null
[注意]firefox浏览器有兼容性问题
<div id="test" style="position:fixed"></div> <script> //firefox并没有考虑固定定位的问题,返回<body>,其他浏览器都返回null console.log(test.offsetParent); </script>
【2】元素自身无fixed定位,且父级元素都未经过定位,offsetParent的结果为<body>
<div id="test"></div> <script> console.log(test.offsetParent);//<body> </script>
【3】元素自身无fixed定位,且父级元素存在经过定位的元素,offsetParent的结果为离自身元素最近的经过定位的父级元素
<div id="div0" style="position:absolute;">
<div id="div1" style="position:absolute;">
<div id='test'></div>
</div>
</div>
<script>
console.log(test.offsetParent); //<div id="div1">
</script>
【4】<body>元素的parentNode是null
console.log(document.body.offsetParent);//null
IE7-浏览器Bug
对于定位父级offsetParent来说,IE7-浏览器存在以下bug
【bug1】当元素本身经过绝对定位或相对定位,且父级元素无经过定位的元素时,IE7-浏览器下,offsetParent是<html>
<div id="test" style="position:absolute;"></div> <script> //IE7-浏览器返回<html>,其他浏览器返回<body> console.log(test.offsetParent); </script>
<div id="test" style="position:relative;"></div> <script> //IE7-浏览器返回<html>,其他浏览器返回<body> console.log(test.offsetParent); </script>
<div id="test" style="position:fixed;"></div> <script> //firefox并没有考虑固定定位的问题,返回<body>,其他浏览器都返回null console.log(test.offsetParent); </script>
【bug2】如果父级元素存在触发haslayout的元素或经过定位的元素,且offsetParent的结果为离自身元素最近的经过定位或触发haslayout的父级元素
[注意]关于haslayout的详细信息移步至此
<div id="div0" style="display:inline-block;">
<div id='test'></div>
</div>
<script>
//IE7-浏览器返回<div id="div0">,其他浏览器返回<body>
console.log(test.offsetParent);
</script>
<div id="div0" style="position:absolute;">
<div id="div1" style="display:inline-block;">
<div id='test'></div>
</div>
</div>
<script>
//IE7-浏览器返回<div id="div1">,其他浏览器返回<div id="div0">
console.log(test.offsetParent);
</script>
<div id="div0" style="display:inline-block;">
<div id="div1" style="position:absolute;">
<div id='test'></div>
</div>
</div>
<script>
//所有浏览器都返回<div id="div1">
console.log(test.offsetParent);
</script>
偏移量
偏移量共包括offsetHeight、offsetWidth、offsetLeft、offsetTop这四个属性
offsetWidth
offsetWidth表示元素在水平方向上占用的空间大小,无单位(以像素px计)
offsetWidth = border-left-width + padding-left + width + padding-right + border-right-width;
offsetHeight
offsetHeight表示元素在垂直方向上占用的空间大小,无单位(以像素px计)
offsetHeight = border-top-width + padding-top + height + padding-bottom + border-bottom-width
<div id="test" style="width:100px; height:100px; padding:10px; margin:10px; border:1px solid black;"></div> <script> //122=1+10+100+10+1 console.log(test.offsetWidth); console.log(test.offsetHeight); </script>
[注意]如果存在垂直滚动条,offsetWidth也包括垂直滚动条的宽度;如果存在水平滚动条,offsetHeight也包括水平滚动条的高度
<div id="test" style="width:100px; height:100px; padding:10px; margin:10px; border:1px solid black; overflow: scroll;"></div>
<script>
//IE8-浏览器将垂直滚动条的宽度计算在width宽度和height高度中,width和height的值仍然是100px;
//而其他浏览器则把垂直滚动条的宽度从width宽度中移出,把水平滚动条的高度从height高度中移出,则滚动条宽度为17px,width宽度和height高度为剩下的83px
if(window.getComputedStyle){
console.log(getComputedStyle(test).width,getComputedStyle(test).height)//83px
}else{
console.log(test.currentStyle.width,test.currentStyle.height);//100px
}
//122=1+10+100+10+1
console.log(test.offsetWidth,test.offsetHeight);
</script>
offsetTop
offsetTop表示元素的上外边框至offsetParent元素的上内边框之间的像素距离
offsetLeft
offsetLeft表示元素的左外边框至offsetParent元素的左内边框之间的像素距离
<div id="out" style="padding: 5px;position: relative;background-color: pink;margin: 10px;">
<div id="test" style="width:100px; height:100px; margin:10px;background-color:green;"></div>
</div>
<script>
//15=test.marginTop(10) + out.paddingTop(5)
alert(test.offsetTop);alert(test.offsetParent)
//15=test.marginLeft(10) + out.paddingLeft(5)
alert(test.offsetLeft);
</script>
IE7-Bug
IE7-浏览器在offsetTop属性的处理上存在bug
【1】若父级设置position: relative,则IE7-浏览器下无法阻止margin传递现象,offsetTop值为offsetParent元素的paddingBottom值
<div id="out" style="padding: 5px;position: relative;">
<div id="test" style="width:100px; height:100px; margin:10px;"></div>
</div>
<script>
//其他浏览器返回15(5+10),而IE7-浏览器返回5
console.log(test.offsetTop);
</script>
【2】若父级设置position: aboslute(或其他触发haslayout的条件),offsetTop值为offsetParent元素的paddingBottom值和当前元素的marginTop值的较大值
<div id="out" style="padding: 5px;position:absolute;">
<div id="test" style="width:100px; height:100px; margin:10px;"></div>
</div>
<script>
//其他浏览器返回15(5+10),而IE7-浏览器返回10(10和5的较大值)
console.log(test.offsetTop);
</script>
页面偏移
要知道某个元素在页面上的偏移量,将这个元素的offsetLeft和offsetTop与其offsetParent的相同属性相加,并加上offsetParent的相应方向的边框,如此循环直到根元素,就可以得到元素到页面的偏移量
[注意]在默认情况下,IE8-浏览器下<html>和<body>的边框宽度都是medium,而其他浏览器是0px
html,body{border: 0;}
body{margin:0;}
function getCSS(obj,attr){
if(window.getComputedStyle){
return getComputedStyle(obj)[attr];
}
return obj.currentStyle[attr];
}
function getElementLeft(element){
var actualLeft = element.offsetLeft;
var current = element.offsetParent;
while(current != null){
actualLeft += current.offsetLeft + parseFloat(getCSS(current,'border-left-width'));
current = current.offsetParent;
}
return actualLeft + 'px';
}
function getElementTop(element){
var actualTop = element.offsetTop;
var current = element.offsetParent;
while(current != null){
actualTop += current.offsetTop + parseFloat(getCSS(current,'border-top-width'));
current = current.offsetParent;
}
return actualTop + 'px';
}
<div style="padding: 20px;border:1px solid black;position:absolute;">
<div id="test" style="width:100px; height:100px; margin:10px;"></div>
</div>
<script>
//其他浏览器返回31(10+20+1),而IE7-浏览器返回21((20和10的较大值)+1)
console.log(getElementTop(test));
//所有浏览器返回31(10+20+1)
console.log(getElementLeft(test));
</script>
注意事项
【1】所有偏移量属性都是只读的
<div id="test" style="width:100px; height:100px; margin:10px;"></div> <script> console.log(test.offsetWidth);//100 //IE8-浏览器会报错,其他浏览器则静默失败 test.offsetWidth = 10; console.log(test.offsetWidth);//100 </script>
【2】如果给元素设置了display:none,则它的偏移量属性都为0
<div id="test" style="width:100px; height:100px; margin:10px;display:none"></div> <script> console.log(test.offsetWidth);//0 console.log(test.offsetTop);//0 </script>
【3】每次访问偏移量属性都需要重新计算
<div id="test" style="width:100px; height:100px; margin:10px;"></div>
<script>
console.time("time");
for(var i = 0; i < 100000; i++){
var a = test.offsetWidth;
}
console.timeEnd('time');//65.129ms
</script>
<div id="test" style="width:100px; height:100px; margin:10px;"></div>
<script>
console.time("time");
var a = test.offsetWidth;
for(var i = 0; i < 100000; i++){
var b = a;
}
console.timeEnd('time');//1.428ms
</script>
由上面代码对比可知,重复访问偏移量属性需要耗费大量的性能,所以要尽量避免重复访问这些属性。如果需要重复访问,则把它们的值保存在变量中,以提高性能。
强烈推荐!好文就要分享。。感谢原作者,让我重新认识了一次偏移量,谢谢!!!
javascript好文---深入理解定位父级offsetParent及偏移大小的更多相关文章
- 深入理解定位父级offsetParent及偏移大小offsetTop / offsetLeft / offsetHeight / offsetWidth
深入理解定位父级offsetParent及偏移大小 [转载] 前面的话 偏移量(offset dimension)是javascript中的一个重要的概念.涉及到偏移量的主要是offsetLeft.o ...
- 深入理解定位父级offsetParent及偏移大小
前面的话 偏移量(offset dimension)是javascript中的一个重要的概念.涉及到偏移量的主要是offsetLeft.offsetTop.offsetHeight.offsetWid ...
- [转]深入理解定位父级offsetParent及偏移大小
偏移量(offset dimension)是javascript中的一个重要的概念.涉及到偏移量的主要是offsetLeft.offsetTop.offsetHeight.offsetWidth这四个 ...
- CSS-position 属性&元素脱离文档流引发父级边框塌陷问题
CSS-position 属性 CSS 定位机制 CSS 有三种基本的定位机制:普通流.浮动(float)和绝对定位(position). 除非专门指定,否则所有框都在普通流中定位.也就是说,普通流中 ...
- javascript好文 --- 深入理解可视区尺寸client
可视区大小 可视区大小client又称为可见大小或客户区大小,指的是元素内容及其内边距所占据的空间大小 clientHeight clientHeight属性返回元素节点的可见高度 clientHei ...
- [jQuery]相对父级元素的fixed定位
(function($) { var DNG = {}; //----------------------------------------------------/ // ...
- CSS文档流与块级元素和内联元素
CSS文档流与块级元素(block).内联元素(inline),之前翻阅不少书籍,看过不少文章, 看到所多的是零碎的CSS布局基本知识,比较表面.看过O'Reilly的<CSS权威指南>, ...
- CSS文档流与块级元素和内联元素(文档)
CSS文档流与块级元素(block).内联元素(inline),之前翻阅不少书籍,看过不 少文章, 看到所多的是零碎的CSS布局基本知识,比较表面.看过O'Reilly的<CSS权威指 南> ...
- CSS文档流、块级元素、内联元素
CSS文档流与块级元素(block).内联元素(inline),之前翻阅不少书籍,看过不少文章, 看到所多的是零碎的CSS布局基本知识,比较表面.看过O'Reilly的<CSS权威指南>, ...
随机推荐
- HDU - 6199 gems gems gems (DP)
有n(2e4)个宝石两个人轮流从左侧取宝石,Alice先手,首轮取1个或2个宝石,如果上一轮取了k个宝石,则这一轮只能取k或k+1个宝石.一旦不能再取宝石就结束.双方都希望自己拿到的宝石数比对方尽可能 ...
- Python中的属性访问与描述符
Python中的属性访问与描述符 请给作者点赞--> 原文链接 在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个nam ...
- 给vagrant中的precise64升级VBoxGuestAdditions
位置:/usr/share/virtualbox/VBoxGuestAdditions.iso 在host(ubuntu 12.04 64)中: 查看虚拟机的名字:jb@H38:~/vm/vagran ...
- day18-socket 编程
1.Socket是网络上的使用的交互信息得方法,也叫套接字 用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. 通讯原理 Soc ...
- Python ORM
本章内容 ORM介绍 sqlalchemy安装 sqlalchemy基本使用 多外键关联 多对多关系 表结构设计作业 ORM介绍 如果写程序用pymysql和程序交互,那是不是要写原生sql语句.如果 ...
- socket编程了解
Socket 编程 Socket通讯原理描述: 套接字是为特定网络协议(例如TCP/IP,ICMP/IP,UDP/IP等)套件对上的网络应用程序提供者提供当前可移植标准的对象.它们允许程序接受并进行连 ...
- day04_09 while循环03
练习题: 3.如何输入一个如下的直角三角形,用户指定输出行数:(如果上下反转,右如何实现?) ********** 以下是自己的思路,没有按照上课老师的思路,反正经过不断的测试改进得出的算法 num ...
- JAVA-json数据与Java的bean类的互相转换
Java调用webservice时用到了json格式的数据,然后就整理这个类.那里不合适的话,希望能够得到指正. public class JsonsAndBeanList { /** * json数 ...
- [办公软件篇][3]windows软件安装
http://www.jeffjade.com/2015/10/19/2015-10-18-Efficacious-win-software/
- A Few Laughing Men
A Few Laughing Men CodeChef - LAUGHMEN Balaji is a great person to hang out with. He tells really am ...