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高度为剩下的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;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>
复制代码

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

强烈推荐!好文就要分享。。感谢原作者,让我重新认识了一次偏移量,谢谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432548.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bash中将字符串split成数组的方法

相信编程时&#xff0c;字符串的处理是很频繁被处理的问题&#xff0c;其中大家肯定不陌生各种语言的string.split(sp)将字符串按照某个字符或子串切分成一个数组。 同样&#xff0c;我们在用shell处理文本信息时也可以方便地实现该功能。 这里主要使用了bash中关于字符串变量的…

mysql的seq2_DESeq2处理TCGA数据库Seq-count数据

1、DESeq2需要导入两个数据集&#xff1a;mycounts, colData。先说mycounts&#xff0c;这就是处理完的TCGA数据RNAmatrix.txt&#xff0c;直接读入即可。library(tidyverse)library(DESeq2)#导入数据setwd("E:/2.Hitseq_counts/")mycountshead(mycounts)#这里有个x&…

理解 e.clientX,e.clientY e.pageX

event.clientX、event.clientY 鼠标相对于浏览器窗口可视区域的X&#xff0c;Y坐标&#xff08;窗口坐标&#xff09;&#xff0c;可视区域不包括工具栏和滚动条。IE事件和标准事件都定义了这2个属性 event.pageX、event.pageY 类似于event.clientX、event.clientY&#xff0c;…

基于FlashPaper的文档播放器

本文主要讨论、描述了使用Adobe公司的Flex与FlashPaper产品完成对发布到网上的文档资料进行只读控制&#xff0c;也就是说只允许浏览操作、对下载、打印进行控制。FlashPaper FlashPaper是Macromedia的一款用于将操作系统所识别的文档的内容通过虚拟打印机制将内容转换为swf文件…

mysql列调换位置_mysql互换表中两列数据方法

1.创建表及记录用于测试CREATE TABLE product ( id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 产品id, name varchar(50) NOT NULL COMMENT 产品名称, original_price decimal(5,2) unsigned NOT NULL COMMENT 原价, price decimal(5,2) unsigned NOT NULL COMMENT 现…

UCScript——C++集成脚本

使用UCScript作脚本&#xff0c;主要是因为它几个特点很适合用于集成&#xff08;脚本引擎体积小&#xff0c;占用资源少&#xff0c;运行快&#xff0c;跨平台跨语言&#xff0c;与宿主语言交互方便&#xff09;&#xff0c;而且它的语法类C语言&#xff0c;不用去多学一门语言…

python经纬度转换xy坐标公式 pyqt_EXCEL公式进行经纬度与XY坐标的相互转换

一、用EXCEL进行高斯投影换算从经纬度B、L换算到高斯平面直角坐标X、Y(高斯投影正算)&#xff0c;或从X、Y换算成B、L(高斯投影反算)&#xff0c;一般需要专用计算机软件完成。在目前流行的换算软件中不足之处&#xff0c;就是灵活性较差&#xff0c;大都需要一个点一个点地进行…

display:inline-block之用法

HTML的元素有多种display属性&#xff0c;比较常见的有display:none; display:block; display:inline和display:inline-block;等。详细可参阅 W3Schools文档。有些HTML元素自然地带有display:block;样式属性&#xff0c;比如<div><h1>...<h6><p><ul…

java桥_JAVA 桥模式

桥梁模式的用意是“将抽象化(Abstraction)与实现化(Implementation)脱耦&#xff0c;使得二者可以独立地变化”。这句话很短&#xff0c;但是第一次读到这句话的人很可能都会思考良久而不解其意。这句话有三个关键词&#xff0c;也就是抽象化、实现化和脱耦。理解这三个词所代表…

display:inline display:block

display:inline; 元素会被显示为内联元素&#xff0c;元素前后没有换行符. display:block 元素将显示为块级元素&#xff0c;此元素前后会带有换行符. 举例&#xff1a; 1.display:block <span style"display:block">11111111</span><span>2222…

java utf8 byte_byte以及UTF-8的转码规则

https://www.cnblogs.com/hell8088/p/9184336.html多年来闲麻烦&#xff0c;只记录笔记&#xff0c;不曾编写BLOG&#xff0c;本文为原创&#xff0c;如需转载请标明出处废话不说&#xff0c;直奔主题ascii计算机只接受 “高”、“低”电压&#xff0c;所以使用二进制 1 和 …

Unreal4(虚幻4抽茧剥丝)——02章格式化C++和蓝图

本章先写个占位符&#xff0c;原因是具体内容正在构思&#xff0c;希望不和网上已有文章内容出现雷同尽量让读者接受新的知识转载于:https://www.cnblogs.com/hiroshiryu/p/3764013.html

jni c call java_Java通过-jni调用c语言

(4)生成的TestJNI.h文件如下&#xff1a;/* DO NOT EDIT THIS FILE - it is machine generated */#include /* Header for class TestJNI */#ifndef _Included_TestJNI#define _Included_TestJNI#ifdef __cplusplusextern "C" {#endif/** Class: TestJNI* Method…

OpenSceneGraph 笔记–如何导出三角形数据

在OpenSceneGraph开发中&#xff0c;为了方便会经常使用到一些不是三角形片的数据&#xff0c;比如四边形等数据。例如画一个管子用四边形带比用三角形片好计算得多。比如现在我们要画一个由两个平面组成的面&#xff0c;我可以这样做&#xff1a; osg::Geode*geodenewosg::Geo…

自由与限制

#自由与限制##自由 前端&#xff0c;包括html-css-javascript三大基础技术&#xff0c;都是非常能体验出开放自由的。具体说来&#xff0c;因为这三大技术都是以标准先行&#xff0c;html-css的标准由w3c组织制定&#xff0c;js的标准由ECMA制定&#xff0c;都是只有标准&#…

理解GL_TRIANGLE_STRIP等绘制三角形序列的三种方式

GL_TRIANGLE_STRIP绘制三角形方式很多时候令人疑惑&#xff0c;在这里对其运作机理进行解释。 一般情况下有三种绘制一系列三角形的方式&#xff0c;分别是GL_TRIANGLES、GL_TRIANGLE_STRIP和GL_TRIANGLE_FAN。 如下图所示&#xff1a; GL_TRIANGLES是以每三个顶点绘制一个三…

Swift的笔记和参考

好久没来了&#xff0c;趁着新语言Swift发布&#xff0c;继续钻研中&#xff01; Create Class 创建类 &#xff08;重载效果&#xff09; // Create Class 创建类 class MyClass {// Properties 成员变量init() {// Constructor 构造函数}// Method 成员方法func doIt() {prin…

java正则过滤js_JS/Java正则表达式验证

校验密码&#xff1a;6-15位var pwdreg /^[0-9A-Za-z_,.!#$%^*]{6,15}$/;pwdreg.test(phonenum)校验手机号var mobilereg /^0?1[3|4|5|7|8][0-9]\d{8}$/;mobilereg.test(phonenum)只能输入数字(年龄大小)只能输入中文、英文、数字、空格(微信中&#xff0c;关键字&#xff0…

UE4中的字符串转换

虚幻4学习---UE4中的字符串转换(文章来自于UE4官方文档) String Conversions: FString To FName FString To Int32 Float To FString FArrayReaderPtr To FString TArray<uint8> To FString FString To char * --- ( TCHAR_TO_ANSI() ) FString To TCHAR * FString …

DeDeCMS后台批量修改替换sql语句大全

有时候后台文章内容、标题或者锚文本出错&#xff0c;需要修改批量修改&#xff0c;那么就需要用dedecms的sql语句进行批量修改了。 利用dedecms后台SQL命令行工具批量修改内容&#xff0c;路径和超链接等信息。语句 DEDECMS SQL命令批量替换1.更改文章中的内容update dede_add…