元素的大小

上次处理一个问题的时候,遇到了要处理元素的滚动位置,由于基础不扎实,头都搞大了。所以特意来总结下关于DOM元素的大小的的知识点。Dom中没有规定如何确定页面中元素的大小。IE为此率先引入了一些属性,以便开发人员使用。目前所有的浏览器都支持这些属性。

1. 偏移量(offset dimension)

偏移量用于描述元素在屏幕上占用的所有可见空间。元素的可见大小由宽度、高度决定,包括所有内边距、滚动条、边框大小(注意不包含外边距)。通过下列4个属性可以取得元素的偏移量。

  • offsetHeight : 元素在垂直方向上占用的空间的大小,以像素为单位。包含元素的高度(内容的高度 + padding-top + padding-bottom)、(可见的)水平滚动条的高度、上边框高度和下边框高度。

  • offsetWidth : 元素在水平方向上占用的空间的大小,以像素为单位。包含元素的宽度(内容的宽度 + padding-left + padding-right)、(可见的)垂直滚动条的宽度、左边框的宽度和右边框宽度。

  • offsetLeft : 元素的左外边框到包含元素(最近的定位父元素)的左内边距的距离,单位为像素。

  • offsetTop : 元素的上边框到包含元素(最近的定位父元素)的上内边距之间的距离,单位为像素。

其中,offsetLeftoffsetTop 属性与包含元素有关系,包含元素的引用保存在 offsetParent 属性中。offsetParent 属性不一定与 parentNode 的值相等。可以用下面一张图来展示上面几个属性表示的不同大小。

图片

如果想要知道某个元素在页面上的偏移量,将这个元素的 offsetLeftoffsetTop 与其 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;
}

这两个函数利用 offsetParent 属性在DOM层次中逐级向上回溯,将每个层次中的偏移量属性合计到一块。对于简单的CSS布局的页面,这两个函数可以得到非常精确的结果。对于使用表格和内嵌框架布局的页面,由于浏览器实现这些元素的方式不同,应此得到的值也就不太精确了。一般来说,页面中的所有元素都会被包含在几个 <div> 元素中,而这些 <div> 元素的 offsetParent 又是 <body> 元素,所以 getElementLeft()getElementTop() 会返回与 offsetLeftoffsetTop 相同的值。

所有这些偏移量属性都是只读的,而且每次访问他们都需要重新计算,因此,应该尽量避免重复访问这些属性;如果需要重复使用其中某些属性,可以将它们保存在全局变量中,以提高性能。

2. 客户区大小(client dimension)

元素的客户区大小,指的是元素内容及其内边距占据的空间大小。有关各户区域的大小的属性有两个: clientWidthclientHeight 。其中,clientWidth 属性是元素内容区域宽度加上左右内边距宽度;clientHeight 属性是元素内容区高度加上上下内边距高度。下图可以形象的说明这些属性表示的大小。

图片

从字面上看,客户区大小就是元素内部的空间大小,因此滚动条占据的空间不计算在内。一个典型的应用就是取得浏览器的可视窗口的大小,可以使用 ducument.documentElementducument.body (在IE7之前的版本中)的 clientWidthclientHeight;

function getViewport() {
    // 首先检查 document.compatMode 属性。以确定浏览器是否运行在混杂模式下。
    // Safari 3.1 之前的版本不支持这个属性。Chrome、Opera 和 Firefox 大多数情况下都是运行在标准模式下面的。
    if (document.compatMode == "BackCompat") {
        return {
            width: document.body.clientWidth,
            height: document.body.clientHeight
        };
    } else {
        return {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight
        }
    }
}

与偏移量相似,客户区大小也是只读的,也是每次访问的时候都要重新计算的。

3. 滚动大小(scroll dimension)

滚动大小,指的是包含滚动内容的元素的大小。有些元素(例如 <html> 元素),即使没有执行任何代码也能自动的添加滚动条。但是另外一些元素。则需要通过CSS的 overfow 属性进行设置才能滚动。以下是4个与滚动大小相关的属性:

  • scrollHeight: 在没有滚动条的情况下,元素内容的总高度。

  • scrollWidth: 在没有滚动条的情况下,元素内容的总宽度。

  • scrollLeft: 被隐藏在内容区域左侧的像素数。通过这个属性可以改变元素的滚动位置。

  • scrollTop: 被隐藏在内容区域上方的像素数。通过这个属性可以改变元素的滚动位置。

下图展示了这些属性代表的大小。

图片

scrollWidthscrollHeight 主要用于确定元素的实际大小。例如,通常认为 <html> 元素在Web浏览器窗口中滚动的元素(IE6 之前版本运行在混杂模式下时候是 <body> 元素)。因此,带有垂直滚动条的页面总高度就是 document.documentElement.scrollHeight

对于不包含滚动条的页面而言,scrollWidthscrollHeightclientWidthclientHeight 之间的关系并不十分清晰。这种情况下,基于 document.documentElement 查看这些属性会在不同浏览器发现一下不一致的问题,如下所示:

  • Safari 3.1 之前的 scrollWidth 等于 clientWidthscrollHeight 也等于 clientHeight。这组大小都等于浏览器视口大小。

  • Firefox 中这两组属性始终是相同的,但是大小代表的是文档区域的实际尺寸,而非视口的尺寸。

  • Opera、Safari 3.1 及更高版本、Chrome 中的这两组属性是有差别的, 其中 scrollWidthscrollHeight 等于视口的大小,而clientWidthclientHeight 等于文档内容区域的大小。

  • IE (标准模式) 中的这两组属性不相同,其中 scrollWidthscrollHeight 等于文档内容区域的大小。而 clientWidthclientHeight 等于视口大小。

在确定文的那个的高度的时候(包括基于视口的最小高度时),必须取得 scrollWidth/clientWidthscrollHeight/clientHeight 中的最大值,才能保证在跨浏览器的环境下得到精确的结果。下面就是这样的一个例子:

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

通过 scrollLeft 和 scrollTop 属性可以确定元素当前滚动的状态,也可以设置元素的滚动位置。当元素尚未被滚动的时候,这两个属性的值都等于0。

4. 确定元素大小

IE、Firefox 3 及更高版本和 Opera 9.5 及更高版本 都为每个元素提供了一个 getBoundingClientRect() 方法。这个方法返回一个矩形对象,包含4个属性: lefttoprightbottom。这些属性给出了元素在页面中相对于视口的位置。但是,浏览器的实现稍有不同。IE 认为文档的做上角坐标是 (2,2),而Firefox 和 Opera则将传统的 (0,0) 作为起点坐标。因此就需要在一开始检查一下坐标(0,0)处的元素位置,在IE中,会返回(2,2)。在其他浏览器中会返回(0,0)。来看看下面的函数:

function getBoundingClientRect(element){
    if (typeof arguments.callee.offset != 'number'){
        var scrollTop = document.documentElement.scrollTop;
        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 = element.getBoundingClientRect();
    var offset = arguments.callee.offset;

    return {
        right: rect.right + offset,
        left: rect.left + offset,
        top: rect.top + offset,
        bottom: rect.bottom + offset
    };
}

对于不支持 getBoundingClientRect() 的浏览器,可以通过其他的手段获取相同的信息。一般来说,rightleft的差值与 offsetWidth 相等,而 bottomtop 的差值与 offsetHeight 相等。而且 lefttop 属性大致等于前面的 getElmentLeft()getElementTop() 函数取得的值。综上可以创建出一个跨浏览器的函数:

function getBoundingClientRect(element) {
    var scrollTop = document.documentElement.scrollTop;
    var scrollLeft = document.documentElement.scrollLeft;
    if (element.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 = element.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(element);
        var actualTop = getElementTop(element);
        return {
            left: actualLeft - scrollLeft,
            right: actualLeft + element.offsetWidth - scrollLeft,
            top: actualTop - scrollTop,
            bottom: actualTop + element.offsetHeight - scrollTop
        }
    }
}

在某些情况下,这个函数放回的值可能会有所不同,比如使用表格布局或者使用滚动元素的情况下。

本文章参考了 《JavaScript高级程序设计(第二版)》 第十一章中的内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值