偏移量(offset dimension)是javascript中的一个重要的概念。涉及到偏移量的主要是offsetLeft、offsetTop、offsetHeight、offsetWidth这四个属性。当然,还有一个偏移参照——定位父级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高度为剩下的83pxif(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;margin: 6px;border:1px solid black"><div id="test" style="width:100px; height:100px; margin:10px;"></div>
</div>
<script>
//15=test.marginTop(10) + out.paddingTop(5)
alert(test.offsetTop);
//15=test.marginLeft(10) + out.paddingLeft(5)
alert(test.offsetLeft);
</script>    

IE7-Bug

  IE7-浏览器在offsetTop属性的处理上存在bug

  【1】若父级设置position: relative,则在IE7-浏览器下,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-浏览器下如果使用currentStyle()方法获取<html>和<body>(甚至普通div元素)的边框宽度都是medium,而如果使用clientLeft(或clientTop)获取边框宽度,则是实际的数值

html,body{border: 0;}
body{margin:0;}

function getElementLeft(element){var actualLeft = element.offsetLeft;var current = element.offsetParent;while(current != null){actualLeft += current.offsetLeft + current.clientLeft;current = current.offsetParent;}return actualLeft + 'px';
}
function getElementTop(element){var actualTop = element.offsetTop;var current = element.offsetParent;while(current != null){actualTop += current.offsetTop + current.clientTop;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>

  由上面代码对比可知,重复访问偏移量属性需要耗费大量的性能,所以要尽量避免重复访问这些属性。如果需要重复访问,则把它们的值保存在变量中,以提高性能

转载于:https://www.cnblogs.com/bobonote/p/8137887.html

深入理解定位父级offsetParent及偏移大小相关推荐

  1. javascript好文---深入理解定位父级offsetParent及偏移大小

    前面的话 偏移量(offset dimension)是javascript中的一个重要的概念.涉及到偏移量的主要是offsetLeft.offsetTop.offsetHeight.offsetWid ...

  2. javascript中定位父级offsetParent 及偏移大小

    偏移量(offset dimension)是javascript中一个重要的概念.javascript中涉及到偏移的有offsetWidth.offsetHeight.offsetLeft.offse ...

  3. offset家族/`offsetParent`-定位父级/真实宽高:offsetWidth,offsetHeight/offsetLeft和offsetTop

    01-offset家族.真实宽高:offsetWidth,offsetHeight.-真实偏移:margin和定位的偏移组合:offsetLeft和offsetTop <style>.bo ...

  4. width:100%与绝对定位同时存在,偏移出父级容器

    当父级容器内的子元素width设为100%,而子元素又有绝对定位时,子元素伸展超出父级容器,像下面 出现这种情况的原因,width:100%,这个百分之百是相对其定位父级而言的,其定位父级有多宽,这个 ...

  5. CSS-实现不同尺寸大小图片自适应父级DIV

    介绍:有时我们放置图片时,因为父级元素固定了大小导致图片比例失调或者是图片被裁剪,体验非常不好.下面介绍一个简单的方法(初学者,欢迎大家提出建议) HTML: <div class=" ...

  6. 关于DOM基础:DOM子节点:childNodes、父节点:parentNode以及相对父级元素进行定位的offsetParent

    DOM基础: 子节点:chrldNodes 父节点:parentNode 节点类型:nodetype offsetParent 基本概念 子节点:通俗的说就算一个父元素下面包着一个子元素.相当于一种& ...

  7. 子级绝对定位,父级相对定位的由来 --- CSS定位

    CSS定位:将盒子定在某一个位置,所以定位也是在摆放盒子, 按照定位的方式移动盒子. 定位 = 定位模式 + 边偏移 . 定位模式用于指定一个元素在文档中的定位方式.边偏移则决定了该元素的最终位置. ...

  8. html5相对父元素定位,layer弹出层设置相对父级元素定位

    layer弹出层默认是相对body固定定位的,可是项目中一般需要相对某个盒子相对定位,下面是个加载弹层例子: var loadIndex = layer.open({ type: 3, //3 表示加 ...

  9. 工作383:css使absolute相对于父容器进行定位而不是以body(为什么绝对定位(absolute)的父级元素必须是相对定位(relative))...

    借知乎的回答如下解释: 首先,我想告诉你的是,如果父级元素是绝对定位(absolute)或者没有设置,里面的绝对定位(absolute)自动以body定位.这句话是错的. 正确的是:只要父级元素设了p ...

最新文章

  1. Cygwin的安装及在Android jni中的简单使用举例
  2. Nature:揭示人大脑类器官为何缺乏正常人脑特有的细胞亚型和复杂回路
  3. c语言求n个数的最小值博客,C语言中的#define宏定义 求一组数的最大值和最小值(转)...
  4. DL:深度学习框架Pytorch、 Tensorflow各种角度对比
  5. python ConfigParser 小试
  6. LVS nat 负载均衡实验
  7. 安卓模拟器获取服务器信息出错,安卓模拟器客户端与服务器不同步
  8. 信息的Raid存储方式,更安全的保障,更花钱的保障!
  9. datatable DataRow
  10. SLF4J with Logback in a Maven Project | Mograblog
  11. 从数组创建ArrayList
  12. 搭建Windows下基于Eclipse 的 PHP 开发环境
  13. 如何下载Chrome谷歌浏览器历史版本
  14. 软件工程~数据字典例子解释
  15. 淘宝新店铺如何打造爆款
  16. java math 最大值_java 中Math 的常用方法
  17. 傻瓜式部署教程2:docker搭建oracle11g数据库
  18. ROG 冰刃4 在 Ubuntu 环境下安装NVIDIA驱动
  19. IPv6下DHCPv6协议(RFC3315)详细介绍
  20. 基金申请-2:期刊如何批量索引SCIE、EI、ISTP (CPCI)?

热门文章

  1. 怎么用python读取csv文件、并且是读取行-使用python获取csv文本的某行或某列数据的实例...
  2. python基础知识整理-整理了27个新手必学的Python基础知识点
  3. python精通-干货|Python学习必须精通的几个模块
  4. python.freelycode.com-Python日期时间处理: datestuff
  5. python 自动化-利用Python语言实现实验室自动化
  6. 学会python爬虫怎么赚钱-转行学Python有前途吗?Python爬虫怎么赚钱?
  7. 中国最大的python社区-在python数据框中的每一行中查找最大值
  8. 自学python方法-零基础初学Python人工智能的四种学习方法
  9. python百度百科api-Python即时网络爬虫:API说明
  10. python 网站文件下载-python从网站上下载东西