關於offsetLeft與position:relative,margin:auto;的一些關係

對於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;" οnclick="alert('2:'+this.offsetLeft);">

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

<div style="margin-left:30px; margin-top:50px; width:100px; height:100px; background-color:#ff0000;" οnclick="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;" οnclick="alert(this.offsetLeft);">

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

<div style="margin:auto; width:100px; height:100px; background-color:#ff0000; position:relative;" οnclick="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;" οnclick="alert(this.offsetLeft);">

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

<div style="margin:auto; width:100px; height:100px; background-color:#ff0000;" οnclick="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;" οnclick="alert(this.offsetLeft);">

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

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

<div id="d4" style="width:100px; height:100px; background-color:#ff0000; margin-left:10px;" οnclick="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;" οnclick="alert(this.offsetLeft);">

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

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

<div id="d4" style="width:100px; height:100px; background-color:#ff0000; margin-left:10px;" οnclick="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)就是以這個祖先元素爲參考點的

原本就是很簡單的東西,非給自己複雜化了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章