你的位置:首页 > Java教程

[Java教程]DOM盒模型


 

偏移量offset

  偏移量包括元素在屏幕上占用的所有可见的空间。元素的可见大小由其高度、宽度决定,包括所有内边距、滚动条和边框大小(注意,不包括外边距)。
    [注意1]所有偏移量属性都是只读的,而且每次访问他们都需要重新计算
    [注意2]若给元素设置了display:none,则它的四个offset属性都为0
【offsetParent】元素的定位父级,(标准浏览器包括IE8下)
  【1】若元素自身是fixed定位,则offsetParent是null
  【2】若元素有进行过CSS定位(relative\absolute\fixed)的父级,则offsetParent就是在DOM结构中离其最近的进行过CSS定位的父级
  【3】若元素没有进行过CSS定位的父级,则offsetParent是<body>元素
  【4】<body>的offsetParent是null

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>body{  margin: 0;}ul{  margin: 0;  padding: 0;  list-style: none;}.box{  width: 500px;  height: 500px;  background-color: gray;}.list{  height: 300px;  width: 300px;  background-color: #ccc;  border: 10px solid black;}.in{  height: 100px;  width: 100px;  background-color: red;  margin: 10px;  padding: 10px;  border: 1px solid black;}</style></head><body><div class="box" id="box">  <ul class="list" id="list">    <li class="in" id="test">test</li>  </ul>  </div><body><script>var oBox = document.getElementById('box');var oList = document.getElementById('list');var oTest = document.getElementById('test');//<body>的定位父级是nullconsole.log(document.body.nodeName);//没有进行CSS定位的父级,所以定位父级是<body>console.log(oList.offsetParent.nodeName);//没有进行CSS定位的父级,所以定位父级是<body>console.log(oTest.offsetParent.nodeName);document.onclick = function(){  oList.style.position = "relative";  //自身有定位,但父级中没有进行CSS定位的,所以定位父级是<body>  console.log(oList.offsetParent.nodeName);  //oList是oText的进行过CSS定位的父级,所以其定位父级是oList  console.log(oTest.offsetParent.nodeName);}</script></body>  </html>  

 

  【IE7-浏览器bug】
    【1】自身有定位元素(relative\absolute)
      【1.1】若无进行过定位的父级元素,则offsetParent是<html>
      【1.2】若有进行过定位的父级元素,则offsetParent是进行过定位的父级元素
    【2】自身无定位元素(触发haslayout的父元素也具有进行过定位的父级的特征)[与标准相同]
      【1.1】若无进行过定位的父级元素,则offsetParent是<body>
      【1.2】若有进行过定位的父级元素,则offsetParent是进行过定位的父级元素

 

【offsetHeight】元素在垂直方向上占用的空间大小,以像素计。包括元素的高度、(可见的)水平滚动条的高度、上边框高度和下边框高度。
【offsetWidth】元素在水平方向上占用的空间大小,以像素计。包括元素的宽度、(可见的)垂直滚动条的宽度、左边框宽度和右边框宽度。
  [注意]即使元素加上水平或垂直滚动条,offsetWidth跟offsetHeight的值是不会更改的,因为浏览器渲染时把滚动条的宽度(或高度)算在了元素本身的宽度(或高度)中了
【offsetLeft】元素的左外边框至包含元素的左内边框之间的像素距离
【offsetTop】元素的上外边框至包含元素的上内边框之间的像素距离
  其中offsetLeft和offsetTop属性与包含元素有关,包含元素的引用保存在offsetParent属性中。offsetParent属性不一定与parentNode的值相等。例如<td>元素的offsetParent是作为其祖先元素的<table>元素,因为<table>是在DOM层次中距<td>最近的一个具有大小的元素

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>body{  margin: 0;}ul{  margin: 0;  padding: 0;  list-style: none;}.list{  height: 500px;  width: 500px;  background-color: #ccc;  border: 10px solid black;}.in{  height: 100px;  width: 100px;  background-color: red;  margin: 100px;  padding: 100px;  border: 1px solid black;}</style></head><body><ul class="list" id="list">  <li class="in" id="test">test</li></ul><script>var oList = document.getElementById('list');var oTest = document.getElementById('test');//302px 302pxconsole.log(oTest.offsetWidth,oTest.offsetHeight);//110px 110px,而IE7-浏览器输出100pxconsole.log(oTest.offsetTop,oTest.offsetLeft);document.onclick = function(){  oTest.style.overflow = "scroll";  //加入滚动条后,值依然不发生改变  console.log(oTest.offsetWidth,oTest.offsetHeight);  console.log(oTest.offsetTop,oTest.offsetLeft);}</script></body>  </html>  

 

  【firefox的bug】
    当自身有定位元素,有定位父级,且定位父级设置overflow:hidden时,火狐的offsetLeft会减去定位父级相应方向的边框的宽度。

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>body{  margin: 0;}ul{  margin: 0;  padding: 0;  list-style: none;}.list{  height: 500px;  width: 500px;  background-color: #ccc;  border: 10px solid black;  border-left-width: 5px;}.in{  height: 100px;  width: 100px;  background-color: red;  margin: 100px;  padding: 100px;  border: 1px solid black;}</style></head><body><ul class="list" id="list">  <li class="in" id="test">test</li></ul><script>var oList = document.getElementById('list');var oTest = document.getElementById('test');document.onclick = function(){  oList.style.position = "relative";  oList.style.overflow = "hidden";  oTest.style.position = "absolute";  //其他浏览器都输出100 100 而firefox浏览器输出 90 95  console.log(oTest.offsetTop,oTest.offsetLeft);  }</script></body>  </html>    

 

  要知道某个元素在页面上的偏移量,将这个元素的offsetLeft和offsetTop与其offsetParent的相同属性相加,并加上offsetParent的相应方向的边框,如此循环直到根元素,就可以得到元素到页面的偏移量。
    [注意]在默认情况下,IE8-浏览器下<html>和<body>的边框宽度都是medium,而其他浏览器是0px。
    兼容写法如下:

  html,body{    border: 0;  }

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';}  

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>html,body{  border: 0;}body{  margin: 0;}ul{  margin: 0;  padding: 0;  list-style: none;}.list{  height: 500px;  width: 500px;  background-color: #ccc;  border: 10px solid black;}.in{  height: 100px;  width: 100px;  background-color: red;  margin: 100px;  padding: 100px;  border: 1px solid black;}</style></head><body><ul class="list" id="list">  <li class="in" id="test">test</li></ul><script>var oList = document.getElementById('list');var oTest = document.getElementById('test');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';}  oList.style.position = "absolute";console.log(getElementTop(oTest));//所有浏览器都输出110pxconsole.log(getElementLeft(oTest));//所有浏览器都输出110px</script></body>  </html>  

 

客户区大小client  

  元素的客户区大小(client dimension)指的是元素内容及其内边距所占据的空间大小。
    [注意1]若设置为display:none,则值为0
    [注意2]客户区大小是只读的,每次访问都要重新计算

 

【属性】
  有关客户区大小的属性有两个:clientWidth和clientHeight。其中,clientWidth属性是元素内容区宽度+左右内边距宽度。clientHeight属性是元素内容区高度+上下内边距高度。

 

【常用应用】确定浏览器视口大小
  [注意]IE6浏览器在标准模式下,视口大小与<html>大小一致;在怪异模式下,视口大小与<body>大小一致。所以兼容写法为:

function getViewport(){  if(document.compatMode == "BackCompat"){    return{      width: document.body.clientWidth,      height: document.body.clientHeight    };  }else{    return{      width: document.documentElement.clientWidth,      height: document.documentElement.clientHeight    };  }}

<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><body><script>function getViewport(){  if(document.compatMode == "BackCompat"){    return{      width: document.body.clientWidth,      height: document.body.clientHeight    };  }else{    return{      width: document.documentElement.clientWidth,      height: document.documentElement.clientHeight    };  }}//IE7-浏览器返回1895,因为默认有滚动条(可得出滚动条宽度为21px),IE8浏览器返回1916,其他浏览器返回1920console.log(getViewport().width)</script></body>  </html>

 

滚动大小scroll

  滚动大小是指包含滚动内容的元素的大小。有些元素(如html元素)即使没有执行任何代码也能自动添加滚动条;但另外一些元素,则需要通过CSS的overflow属性进行设置才能滚动。

 

【scrollHeight和scrollWidth】
  【scrollHeight】在没有滚动条的情况下,元素内容的总高度
  【scrollWidth】在没有滚动条的情况下,元素内容的总宽度
    [注意]scrollWidth和scrollHeight主要用于确定元素内容的实际大小。通常认为<html>元素就是在Web浏览器的视口中滚动的元素。因此,带有垂直滚动条的页面总高度就是document.documentElement.scrollHeight

 

【scroll和client的区别】
  【1】在有滚动条的情况下,scorllHeight表示元素的实际总高度,而clientHeight表示元素的视觉总高度(宽度也类似)

<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>.box{  height: 100px;  width: 200px;  overflow: scroll;}</style><body><div class="box" id="box">我是测试内容<br>我是测试内容<br>我是测试内容<br>我是测试内容<br>我是测试内容<br>我是测试内容<br>我是测试内容<br>我是测试内容<br>我是测试内容<br></div><script>var oBox = document.getElementById('box');//100 162console.log(oBox.clientHeight,oBox.scrollHeight);//183 183console.log(oBox.clientWidth,oBox.scrollWidth);</script></body>  </html>

 

<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>html{  height: 2000px;}</style><body><script>//500 2000console.log(document.documentElement.clientHeight,document.documentElement.scrollHeight);//1899 1899(IE9+及其他浏览器,说明滚动条的宽度为1920-1899=21px)//1895(IE8-浏览器)console.log(document.documentElement.clientWidth,document.documentElement.scrollWidth);</script></body>  </html>

 

  【2】在无滚动条的情况下,各浏览器的处理不一致
    【2.1】页面有高度时
    [a]firefox和IE8+浏览器中<html>的scrollHeight和clientHeight=可视区高度,<body>的scrollHeight和clientHeight=内容实际高度
    [b]chrome、opera、safari中<html>scrollHeight=内容实际高度,clientHeight=可视区高度;而<body>中scrollHeight=可视区高度,clientHeight=内容实际高度

<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>body{  margin: 0;  line-height: 20px;}</style><body><br><script>//(firefox/IE8+)500 500//(chrome/IE7-/safari/opera)500 20console.log(document.documentElement.clientHeight,document.documentElement.scrollHeight);//(firefox/IE8+/IE7-)20 20//(chrome/safari/opera)20 500console.log(document.body.clientHeight,document.body.scrollHeight);</script></body>  </html>

 

    【2.2】页面无高度时
    [a]firefox和IE浏览器中<html>clientHeight=scrollHeight=当前可视区高度,<body>的clientHeight=scrollHeight=0
    [b]chrome、opera、safari中,<html>clientHeight=当前可视区高度,scrollHeight=0;<body>clientHeight=0,scrollHeight=当前可视区高度

<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>body{  margin: 0;}</style><body><script>//(firefox/IE/)500 500//(chrome/safari/opera)500 0console.log(document.documentElement.clientHeight,document.documentElement.scrollHeight);//(firefox/IE8)0 0 //(chrome/safari/opera)0 500console.log(document.body.clientHeight,document.body.scrollHeight)</script></body>  </html>  

 

    【2.3】元素无滚动条时
    [a]IE7-浏览器的可视高为设置的高度,而滚动高为子元素的实际高度
    [b]其他浏览器的可视高等于滚动高都等于设置的高度

<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>.box{  height: 100px;}</style><body><div class="box" id="box">  12440<br>  12440<br>  12440<br></div><script>var oBox = document.getElementById('box');//IE7-浏览器的可视高为设置的高度100,而滚动高为子元素的实际高度57//其他浏览器的可视高等于滚动高都等于100console.log(oBox.clientHeight,oBox.scrollHeight);</script></body>  </html>

 

   因此要取得文档实际高度时,要取得<html>元素的scrollHeight和clientHeight的最大值

  var docHeight = Math.max(document.documentElement.scrollHeight,document.documentElement.clientHeight);  var docWidth = Matn.max(document.documentElement.scrollWidth,document.documentElement.clientWidth);

 

【scrollLeft和scrollTop】
  通过scrollLeft和scrollTop属性既可以确定元素当前滚动的状态,也可以设置元素的滚动位置。


  【scrollLeft】被隐藏在内容区域左侧的像素数。元素未滚动时,scrollTop的值为0,如果元素被水平滚动了,scrollLeft的值大于0,且表示元素左侧不可见内容的像素宽度。
  【scrollTop】被隐藏在内容区域上方的像素数。元素未滚动时,scrollTop的值为0,如果元素被垂直滚动了,scrollTop的值大于0,且表示元素上方不可见内容的像素宽度。


  【页面滚动条的兼容】
    对于firefox及IE浏览器,使用document.documentElement.scrollTop可获得页面的滚动高度
    对于chrome、safari、opera基于webkit的浏览器,使用document.body.scrollTop可获得页面的滚动高度
    所以兼容写法是

var docScrollTop = document.documentElement.scrollTop || document.body.scrollTop

<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>body{  margin: 0;  line-height: 2000px;}</style><body><br><script>document.onclick = function(){  document.title = (document.documentElement.scrollTop || document.body.scrollTop);}</script></body>  </html>

 

元素大小getBoundingClientRect()

  getBoundingClineRect()方法返回一个矩形对象,各个浏览器返回的对象包含的属性不相同
    (firfox):top/left/right/bottom/width/height/x/y[x=left,y=top]
    (chrome\safari\opera\IE9+):top/left/right/bottom/width/height
    (IE8-):top/left/right/bottom
  [注意1]该方法的所有属性值都没有单位,且给定的是元素在页面中相对于视口的位置
  [注意2]IE7-浏览器认为视口的左上角坐标是(2,2),其他浏览器则将(0,0)作为起点坐标。
  兼容写法:(利用IE7-浏览器中特性节点的specified属性)

function getBoundingClientRect(obj){  var temp = obj.getBoundingClientRect();  //IE7-浏览器  if(Boolean(obj.attributes[0]) && !obj.attributes[0].specified){    return{      left: temp.left -2,      top: temp.top -2,      right: temp.right -2,      bottom: temp.bottom -2    }  }else{    return temp;  }  }

<!DOCTYPE HTML><html lang="en"><head><meta charset="UTF-8"><title>Document</title><style>body{  margin: 0;  line-height: 50px;}.box{  width: 100px;  height: 100px;  padding: 10px;  border: 1px solid black;  background-color: lightgreen;}</style><body><div>  测试内容<br>  测试内容<br>  测试内容<br>  测试内容<br>  测试内容<br></div><div class="box" id="box"></div><div>  测试内容<br>  测试内容<br>  测试内容<br>  测试内容<br>  测试内容<br></div><script>var oBox = document.getElementsByTagName('div')[1];function getBoundingClientRect(obj){  var temp = obj.getBoundingClientRect();  //IE7-浏览器  if(Boolean(obj.attributes[0]) && !obj.attributes[0].specified){    return{      left: temp.left -2,      top: temp.top -2,      right: temp.right -2,      bottom: temp.bottom -2    }  }else{    return temp;  }  }document.onclick = function(){  console.log(getBoundingClientRect(oBox).top,document.body.scrollTop);  }</script></body>  </html>