CSSOM视图模型中几个常用的位置、尺寸以及解决方案

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和clientHeightclientLeft和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和offsetHeightoffsetWidth和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;
}
offsetLeft和offsetTop相对于根元素的偏移量

滚动大小

滚动大小属性有 scrollLeft和scrollTopscrollWidth和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起点坐标

对于求元素在页面中的偏移,我们有以下任务要完成:

  1. 不支持getBoundingClientRect用元素视图属性中的offsetLeft和offsetTop和scrollLeft和scrollTop
  2. 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)的所有对象属性。

本文源链接:http://www.html5jscss.com/js-size-top-left.html

转载请注明《CSSOM视图模型中几个常用的位置、尺寸以及解决方案》| html5jscss

评论关闭了.