Web页面空间是包含在浏览器的边框中的所有区域:浏览器的外边缘、状态栏和菜单栏。如果页面内容比窗口去要打,浏览器会添加垂直或者水平滚动条,以便你可以滚动以查看所有页面内容。
CSSOM视图模型在我们日常工作时密不可分,在2011年8月份,W3C新增加了直接的API可以直接使用,但是因为浏览器不兼容,所以我们在使用新属性时尽量做到向后兼容。以下就是针对innerWidth和innerHeight、getBoundingClientRect和pageX和pageY的几套向后兼容的方案和详细介绍,其中还介绍了几中常见元素视图属性。
浏览器可视化区域
innerWidth和innerHeight是Window视图属性的对象属性,支持大多数浏览器,包括Firefox、Chrome、Safari和Opera,它返回窗口的可视化区域(除去滚动条),然而IE不支持window的innerWidth和innerHeight,我们就可以通过clientWidth和clientHeight来访问window的宽度和高度。
可视化区域大小,指的是元素内容以及其内边距(padding+width)
元素的可视化区域
可视化区域的属性有clientWidth和clientHeight
和clientLeft和clientTop
clientWidth和clientHeight可以表示元素内容的可视化区域,包括padding大小,但是不包括边框和滚动条。
元素视图属性跟clientWidth和clientHeight相关的还有属性对象,表示内容区域的左上角相对于整个元素左上角的位置,相当于边框大小,这里我们不做详细介绍了~,感觉兼容性不是很好。
要确定浏览器的可视化区域,clientWidth和clientHeight在现有浏览器里都是兼容的(IE5兼容),但是在混杂模式下,得通过documentView属性提供宽度和高度。所以在IE中我们可以使用如下三元运算符来访问浏览器的可视化区域大小。
wdth = (document.documentElement.clientWidth?document.documentElement.clientWidth:document.body.clientWidth); hth = (document.documentElement.clientHeight?document.documentElement.clientHeight:document.body.clientHeight);
最终我们得到以下结论来解决浏览器可视化区域的兼容性:
- 所有浏览器除了IE:window.innerWidth, window.innerHeight,返回窗口的视口区域,减去任何滚动条大小。
- IE with DOCTYPEL:document.documentElement.clientWidth, document.documentElement.clientHeight,IE通过documentView属性提供视口信息。
- IE without DOCTYPE:document.body.clientWidth, document.body.clientHeight,混杂模式获取视口信息
兼容浏览器可视化区域方案
function getViewport(){ var wdth= 0; var hth= 0; if(!window.innerWidth){ wdth = (document.documentElement.clientWidth?document.documentElement.clientWidth:document.body.clientWidth); hth = (document.documentElement.clientHeight?document.documentElement.clientHeight:document.body.clientHeight); }else{ wdth = window.innerWidth; hth = window.innerHeight; } return{width:wdth ,height:hth} } //通过一下代码访问宽度和高度 window.onload = function(){ var viewPort = getViewport(); var w = viewPort.width; var h = viewPort.height; }
页面中元素偏移
得到矩形元素的界线,返回的是一个对象,包含 top, left, right, 和 bottom四个属性值,大小都是元素相对于页面上右下左的偏移大小。
getBoundingClientRect 以前是IE专有的属性,后来W3C将它扶正为标准。IE、firefox3以及更高版本和Opera9.5以及更高版本为每个元素都提供了一个getBoundingClientRect()方法。这个方法返回一个矩形对象,包含4个属性值:left、top、right和bottom。这些属性给出了元素在页面中相对于视口的位置。但是由于兼容性问题,我们往往采用偏移量和滚动大小相加来求在页面中的位置。
偏移量
偏移量的属性有offsetWidth和offsetHeight
和offsetWidth和offsetHeight
- offsetHeight:元素在垂直方向上占用的大小。包括元素的可见高度、水平滚动条的高度、上下边框的宽度。
- offsetWidth:元素在垂直方向上占用的大小。包括元素的可见宽度、垂直滚动条的宽度、上下边框的宽度。
- offsetLeft:元素的左外边框至包含元素的左内边框之间的像素距离
- offsetTop:元素的上外框至包含元素的上内边框之间的像素距离
偏移量跟可视化的属性区别是:前者的对比对象是包含的元素,而后者对比对象是自己;clientWidth和clientHeight的区域是包括padding的区域,而offsetWidth和offsetHeight则是在所包含元素中占的位置大小;clientLeft和clientTop的值跟border的值一样,而offsetWidth和offsetHeight的值则是相对于包含元素的距离。
所有以上距离跟margin无关。
其中offsetLeft和offsetTop属性与包含元素有关,包含属性的引用保存在offsetParent属性中。所以想知道某个元素在页面上的偏移量,将这个元素的offsetLeft和offsetTop与其offsetParent的相同属性相加,如此循环直至根元素,就可以得到元素偏移浏览器的偏移量了,如下函数:
function getElementLeft(element){ var actualLeft = element.offsetLeft; var current = element.offsetParent; while(current!==null){ actualLeft +=current.offsetLeft; current = current.offsetParent; } return actualLeft; } function getElementTop(element){ var actualTop = element.offsetTop; var current = element.offsetParent; while(current!==null){ actualTop +=current.offsetTop; current = current.offsetParent; } return actualTop; }
滚动大小
滚动大小属性有 scrollLeft和scrollTop
和scrollWidth和scrollHeight
,指的是包含内容元素的大小。
- scrollTop:元素垂直滚动的像素大小。
- scrollHeight:元素水平滚动的像素大小。
- scrollHeight:在没有滚动条的情况下,元素的总高度;则当有垂直方向有滚动条的话,scrollHeight应该等用于scrollTop + clientHeight
- scrollWidth:在没有滚动条的情况下,元素的总宽度;则当有垂直方向有滚动条的话,scrollWidth应该等用于scrollLeft + clientWidth
看完偏移量和滚动大小,我们在回过头来看getBoundingClientRect对象。getBoundingClientRect对象有一个怪现象,IE7会将(2,2)作为起点坐标,IE其他版本、firefox等现代浏览器中将(0,0)作为起点坐标。
function positionObject(obj){ var rect = obj.getBoundingClientRect(); return[rect.top,rect.left]; }
对于求元素在页面中的偏移,我们有以下任务要完成:
- 不支持getBoundingClientRect用元素视图属性中的offsetLeft和offsetTop和scrollLeft和scrollTop
- IE7中元素起点不是(0,0)
利用上面getElementLeft和getElementTop我们得到如下方案:
function getBoundingClientRect(elemrnt){ var scrollTop = document.documentElement.scrollTop; var scrollLeft = document.documentElement.scrollLeft; if(elemrnt.getBoundingClientRect()){ if(typeof arguments.callee.offset!="number"){ var temp = document.createElement("div"); temp.style.cssText = "position:absolute;left:0;top:0;" document.body.appendChild(temp); arguments.callee.offset = -temp.getBoundingClientRect().top-scrollTop; document.body.removeChild(temp); temp = null; } var rect = elemrnt.getBoundingClientRect(); var offset = arguments.callee.offset; return{ left:rect.left+offset, right:rect.right+offset, top:rect.top+offset, bottom:rect.bottom+offset }; }else{ var actualLeft = getElementLeft(elemrnt); var actualTop = getElementTop(elemrnt); return{ left:actualLeft-scrollLeft, right:actualLeft+elemrnt.offsetWidth-scrollLeft, top:actualTop-scrollTop, bottom:actualTop+elemrnt.offsetHeight-scrollTop } } }
鼠标位置
与鼠标事件(例如普通的单击)相关的属性很多,但是,但是常用貌似只有clientX和clientY
clientX和clientY返回鼠标事件时鼠标相对于浏览器窗口左上角的偏移位置。
日常应用案例:捕捉鼠标点击位置
function catchMouse(evt){ evt= evt||window.event; var x = 0; var y =0; if(evt.pageX){ x = evt.pageX; y = evt.pageY; }else if(evt.clientX){ if(document.documentElement.scrollTop){ offsetX = document.documentElement.scrollLeft; offsetY = document.documentElement.scrollTop; }else if(document.body){ offsetX = document.body.scrollLeft; offsetY = document.body.scrollTop; } x = evt.clientX+offsetX; y = evt.clientY+offsetY; } }
为了兼容浏览器兼容问题,一个鼠标位置用了那么代码~
像firefox等现代浏览器,可以直接通过Event对象作为事件处理程序的一个参数传递,而在IE8之前我们只能通过Window对象访问Event对象,所以我们使用
evt= evt||window.event;
而IE8以下浏览器不知pageX和pageY属性来获得Web页面中鼠标的位置。所以我们clientX和clientY再加上滚动条滚动的长度就能计算得出Web页面中鼠标的位置
好了,几中常见的CSSOM视图模型就介绍到了,以后有机会再研究下CSSOM视图模式(CSSOM View Module)的所有对象属性。