深入理解定位父级offsetParent及偏移大小

摘要:
偏移量是javascript中的一个重要概念。OffsetLeft、offsetTop、offsetHeight和offsetWidth是与偏移相关的四个属性。本文将详细介绍在了解偏移量大小之前必须先了解offsetParent。

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

深入理解定位父级offsetParent及偏移大小第1张

定位父级

在理解偏移大小之前,首先要理解offsetParent。人们并没有把offsetParent翻译为偏移父级,而是翻译成定位父级,很大原因是offsetParent与定位有关

定位父级offsetParent的定义是:与当前元素最近的经过定位(position不等于static)的父级元素,主要分为下列几种情况

【1】元素自身有fixed定位,offsetParent的结果为null

当元素自身有fixed固定定位时,我们知道固定定位的元素相对于视口进行定位,此时没有定位父级,offsetParent的结果为null

[注意]firefox浏览器有兼容性问题

<div   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   style="position:absolute;">
    <div   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   style="position:absolute;"></div>    
<script>
//IE7-浏览器返回<html>,其他浏览器返回<body>
console.log(test.offsetParent);
</script>
<div   style="position:relative;"></div>    
<script>
//IE7-浏览器返回<html>,其他浏览器返回<body>
console.log(test.offsetParent);
</script>
<div   style="position:fixed;"></div>    
<script>
//firefox并没有考虑固定定位的问题,返回<body>,其他浏览器都返回null
console.log(test.offsetParent);
</script>

【bug2】如果父级元素存在触发haslayout的元素或经过定位的元素,且offsetParent的结果为离自身元素最近的经过定位或触发haslayout的父级元素

[注意]关于haslayout的详细信息移步至此

复制代码
<div   style="display:inline-block;">
    <div id='test'></div>    
</div>
<script>
//IE7-浏览器返回<div id="div0">,其他浏览器返回<body>
console.log(test.offsetParent);
</script>
复制代码
复制代码
<div   style="position:absolute;">
    <div   style="display:inline-block;">
        <div id='test'></div>    
    </div>    
</div>
<script>
//IE7-浏览器返回<div id="div1">,其他浏览器返回<div id="div0">
console.log(test.offsetParent);
</script>
复制代码
复制代码
<div   style="display:inline-block;">
    <div   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   style="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   style="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   style="padding: 5px;position: relative;margin: 6px;border:1px solid black">
    <div   style="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   style="padding: 5px;position: relative;">
    <div   style="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   style="padding: 5px;position:absolute;">
    <div   style="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   style="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   style="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   style="100px; height:100px; margin:10px;display:none"></div>
<script>
console.log(test.offsetWidth);//0
console.log(test.offsetTop);//0
</script>

【3】每次访问偏移量属性都需要重新计算

复制代码
<div   style="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   style="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>
复制代码

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

免责声明:文章转载自《深入理解定位父级offsetParent及偏移大小》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇PetShop 4.0 详解之四(PetShop之ASP.NET缓存)Eclipse 3.5使用dropins的插件安装方式下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

利用after和before实现的一些效果

整理网上利用after和before实现的一些效果(以备用) 1.实现如图所示效果: .index-notice{height: 45px;line-height: 45px;margin-top: 5px;border-bottom: 1px solid #e5e5e5;position: relative} .index-notice span{fon...

工作笔记

更改过程让数据不时时更新 let add = JSON.stringify(editMarketChannel);this.editMarketChannel = JSON.parse(add); 这个为函数传入的对象,Obj 提示信息 成功的 this.msgs = [];this.msgs.push({severity:'success', summa...

css设置文字中间的小竖线

主要css属性是border-right border-right:1px solid gray; padding-right:10px; padding-left:10px; <div data-bind="foreach:RequestListAll"> <a data-bind="text:PositionName...

巧用 BootStrap -- 栅格系统(布局)轻松搞定网页响应式布局!

  摘要:Bootstrap 为我们提供了一套响应式、移动设备优先的流式栅格系统,合理的使用栅格系统将会使得网站页面布局变得更加简单,在设置了媒体查询之后,响应式网站也无需再单独写了。接下来我以Bootstrap的中文官网首页为模板进行展示其栅格布局的使用方法以及相关知识点。相信在看完这篇文章之后,你完全可以轻松使用栅格布局。 网站效果图如下所示: P...

WebLesson04盒子模型,浮动+定位 17王晶龙

一、盒子模型   盒子模型是由内容(content)、边框(border)、外边距(margin)、内边距(padding)组成   1.border:边框宽度,颜色,样式     border-width:     border-color:     border-style:  solid实线 dashed虚线 dotted点线 double双边框bo...

Windows App开发之集成设置、帮助、搜索和共享

应用设置和应用帮助 ”设置“合约 上一节中我们学习了如何将应用设置保存到本地,这种方式是通过在App内添加设置选项,这里还有一种方式。微软将其称为“设置”合约,并且所有的Windows应用商店应用都将自动配合这种合约。但是应用自带的这种设置如果不做任何修改可谓毫无作用。而我们添加这些设置则可以让应用更加个性化哦。 SettingsFlyout...