关于offsetLeft与position:relative,margin:auto;的一些关系

来源:互联网 发布:nba变态数据 编辑:程序博客网 时间:2024/05/17 23:53

对于div的offsetLeft或offsetTop属性,它与postion的关系十分密切。


默认情况下是position:static;在position为static(即没有设置positoin属性,或position为空时)。

1.在ie7(ie6没有环境测试估计一样)中,div的offsetLeft的值是当前div左边框到它父级div左内边框的像素距离,对于它的父级div的position对它的结果没有影响。

2.在ie8,ie9,firefox,chorme中,祖先级的position对这个结果的影响是明显的,因为div的offsetLeft的值是当前div左边框到它祖先级中第一个带position:relative;或position:absolute属性的元素的像素距离。

以下代码在ie7,ie8,ie9,firefox,chrome下证明了这一点

<body style="margin:0px;">

<div style="margin-left:30px; margin-top:50px; width:300px; height:300px; background-color:#330000; position:absolute;" onclick="alert('2:'+this.offsetLeft);">

<div style="margin-left:30px; margin-top:50px; width:200px; height:200px; background-color:#333300;" onclick="alert('1:'+this.offsetLeft);">

<div style="margin-left:30px; margin-top:50px; width:100px; height:100px; background-color:#ff0000;" onclick="alert('0:'+this.offsetLeft);"></div>

</div>

</div>

</body>



postion:relative(或absolute)来时,ie7,ie8,ie9,firefox,chrome下的表示是一致的。

position:relative;的div的offsetLeft的取值,与其祖先级div的postion值密切相关。如果position:relative;的div的祖先div都是postion:static;的话,那么这个div的offsetLeft的值就是当前div左边框到body的像素距离了,如果祖先div中有postion:relative;或position:absolute;的div,则当前div的offsetLeft的值就是当前div左边框到距离当前div最近的带有postion:relative;或position:absolute的祖先的像素距离。



在margin不为auto时

当margin为auto时,ie7和ie8,ie9,firefox,chrome表现出来的结果是很不一样的。以下是我的测试代码一:

<body style="margin:0px;">

<div style="margin:auto; width:300px; height:300px; background-color:#330000;" onclick="alert(this.offsetLeft);">

<div style="margin:auto; width:200px; height:200px; background-color:#333300;" onclick="alert(this.offsetLeft);">

<div style="margin:auto; width:100px; height:100px; background-color:#ff0000; position:relative;" onclick="alert(this.offsetLeft);"></div>

</div>

</div>

</body>

此时在ie7上的表现跟我最开始的描述是一致的,就是说margin对ie的offsetLeft是没有任何影响的。但是在ie8,ie9,firefox,chrome下的表现就奇怪了。点击最里层的div,弹出的数依次是670,620,570这说明了加了margin:auto;后div的offsetLeft的取值直接就是当前div到body的距离。事实真是所有的带margin:auto的div的offsetLeft都是以body为参照取值吗?我觉得不可能,于是又改了代码,如下:

<body style="margin:0px;">

<div style="margin:auto; width:300px; height:300px; background-color:#330000;" onclick="alert(this.offsetLeft);">

<div style="margin:auto; width:200px; height:200px; background-color:#333300; position:relative;" onclick="alert(this.offsetLeft);">

<div style="margin:auto; width:100px; height:100px; background-color:#ff0000;" onclick="alert(this.offsetLeft);"></div>

</div>

</div>

</body>

再点击最里层的div,弹出的数依次是

50,620,570

这里的表现直接就说明了ie8,ie9,firefox,chrome下,加了margin:auto;的div的offsetLeft的取值与position:relative的取值是一样的,但是加了margin:auto;的div不等于于position:relative的div,一个重要的依据是带position:relative的div(或是margin:auto;)在实际计算中不把margin:auto;的祖先当做计值参照。所以这里在记忆上可能会造成混乱。

总结:带margin:auto的div在计算offsetLeft时与position:relative是一样的,但是被计算是不按postion:relative看待,以实际position为准。

这个原因可能会造成ie8,ie9,firefox,chrome不能定位。

关于margin:auto;ie8,ie9,firefox,chrome下的再补充,上面的例子还不够说明margin:auto在ie8,ie9,firefox,chrome下的一些特殊性,

以下是新测试代码一:

<body style="margin:0px;">

<div id="d1" style="margin:auto; width:300px; height:300px; background-color:#330000;" onclick="alert(this.offsetLeft);">

<div id="d2" style="width:250px; height:250px; background-color:#003333; margin-left:15px;" onclick="alert(this.offsetLeft);">

<div id="d3" style="margin:auto; width:200px; height:200px; background-color:#333300;" onclick="alert(this.offsetLeft);">

<div id="d4" style="width:100px; height:100px; background-color:#ff0000; margin-left:10px;" onclick="alert(this.offsetLeft);"></div>

</div>

</div>

</div>

</body>

点击d4后依次弹出的数值是:620,610,585,570

这里是让我产生margin:auto在ie8,ie9,firefox,chrome下对offsetLeft的影响不止于以上所说的例子。照理说d4应该是10而不应该是620,但是它是620,说明ie8,ie9,firefox,chrome对margin:auto;div的子孙级div也是有特殊处理的。于是改变代码如下,新测试代码二:

<div id="d1" style="margin:auto; width:300px; height:300px; background-color:#330000;" onclick="alert(this.offsetLeft);">

<div id="d2" style="width:250px; height:250px; background-color:#003333; margin-left:15px; position:relative;" onclick="alert(this.offsetLeft);">

<div id="d3" style="margin:auto; width:200px; height:200px; background-color:#333300;" onclick="alert(this.offsetLeft);">

<div id="d4" style="width:100px; height:100px; background-color:#ff0000; margin-left:10px;" onclick="alert(this.offsetLeft);"></div>

</div>

</div>

</div>

点击d4后依次弹出的数值是:35,25,585,570

d4把带有属性position:relative的d2,当做offsetLeft的参照做计算了。

于是,反复更改代码测试,最后得出一个更完善的结论:

ie8,ie9,firefox,chrome下,带margin:auto的div在计算offsetLeft时与position:relative是一样的,但是被计算是不按postion:relative看待,以实际position为准;并且margin:auto;的div的子孙div都有如上相同的特性(其实就是继承);

以上的论述,会造成ie8,ie9,firefox,chrome下计算定位的难度,以下是我写的用于定位的js:


function L_getpos(obj)
{
 var left=0;
 var top=0;
 var oleft=obj.offsetLeft;
 var otop=obj.offsetTop;//oleft,otop原点坐标
 var rleft=0;
 var rtop=0;//position:relative的祖先元素的offsetLeft和offsetTop的累计和
 var relative=false;//与position相关,如果遇到父级的属性为relative或absolute时,此属性为true,为true之后的left和top取值,只取position为relative或absolute的div的offsetLeft和offsetTop
 var marginAuto=false;//祖先级中有没有margin:auto的属性,ie8,ie9,firefox,chrome是重要的判断
 var parentNode=obj;
 do{
  if(getCss(parentNode,"position")=="relative" || getCss(parentNode,"position")=="absolute")
  {
   relative=true;
  }
  if((getCss(parentNode,"margin")).indexOf("auto")>=0)
  {//这里有个bug,firefox下如果把margin属性写在css文件中的话,没有办法获取这个属性,会造成计算结果不准
   marginAuto=true;
  }else{//chrome的兼容
   if(getCss(parentNode,"marginLeft")==getCss(parentNode,"marginRight"))
   {
    marginAuto=true;
   }
  }
  if(!relative)
  {
   left+=parentNode.offsetLeft;
   top+=parentNode.offsetTop;
  }else{
   if(getCss(parentNode,"position")=="relative" || getCss(parentNode,"position")=="absolute")
   {
    rleft+=parentNode.offsetLeft;
    rtop+=parentNode.offsetTop;
   }
  }
  parentNode=parentNode.parentNode;
 }
 while(parentNode.tagName.toLowerCase()!="body")
 var hack=document.getElementById("__hack__");
 var firfoxchromeie8ie9=false;//判断浏览器
 if(hack==null)
 {
  var hackHtml=document.createElement('<div style="background-color:#000000; background-color:#888888\\0; background-color:#999999\\9\\0; *background-color:#777777; _background-color:#666666;" id="__hack__" ></div>');
  document.getElementsByTagName("body")[0].appendChild(hackHtml);
  hack=document.getElementById("__hack__");
 }
 var version=hack.style.backgroundColor;
 if(version=="#000000" || version=="rgb(0, 0, 0)" || version=="#888888" || version=="rgb(153, 153, 153)")
 {
  firfoxchromeie8ie9=true;
 }
 if(firfoxchromeie8ie9 && (relative || marginAuto))
 {
  left=oleft+rleft;
  top=otop+rtop;
 }else if(relative){
  left+=rleft;
  top+=rtop;
 }
 return {left:left,top:top};
}
function getCss(obj, prop) {     //IE中使用的是obj.currentStyle方法,而FF是用的是getComputedStyle 方法
 //if(typeof(obj.style[prop])!="undefined")
 if(obj.style[prop]!="")
 {
  return obj.style[prop];
 }
   if (obj.currentStyle) {     //判断IE
        return obj.currentStyle[prop];     
   }     
    else if (window.getComputedStyle) {     //判断FF 
        propprop = prop.replace (/([A-Z])/g, "-$1");           
       propprop = prop.toLowerCase ();        
         return document.defaultView.getComputedStyle (obj,null)[prop];
    }      
    return null;   
}

这里会有个bug,在firefox下,如果margin:auto;被写在外部文件中的话,那么目前据我所知没有办法准确地去判断当前元素有没有margin:auto;属性。避免出错的方法就是在所有带margin:auto的元素中加入position:relative;

 

唉,坑爹了。。。今天才发现有个叫offsetparent的东西!!!!这个可以完美解决我上述说得如此复杂的东西,

offsetParent:是指元素最近的定位(relative,absolute)祖先元素,如果没有祖先元素是定位的话,会指向body元素

       作用:元素的偏移量(offsetLeft,offsetTop)就是以这个祖先元素为参考点的

原本就是很简单的东西,非给自己复杂化了。
0 0