找到最远的DIV的最便宜的方式?

时间:2012-12-24 08:38:02

标签: javascript css html position dimensions

假设我们有一个未知widthheight的容器div,它小于身体的整个尺寸。

此容器div包含未知数量的div。容器中的所有div都具有不同大小,除此之外,它们具有与以下3种类型之一相同的CSS:

  • 类型1:所有div都浮动到左侧。
  • 类型2:所有div都是 漂浮在右边。
  • 类型3:所有div都有未知的绝对值 位置,甚至可以远离屏幕。

类型1和2 div具有边距,可能也有填充。类型3 div可以有,也可以两者都没有。

鉴于容器中div的类型未知 - 最终目标是在原始内部添加一个辅助容器,其大小足以容纳视口中的所有div(带溢出:滚动)。 最便宜的计算方法是什么?

要记住的一些事情:

  1. div 可能<也不是(整体而言)box-sizing: border-box。这将影响它们的边框,边距和填充的呈现方式,也应该考虑在内。

  2. 在类型1和类型2(浮动div)的情况下,div意味着水平堆叠 - 即,容器应该增长以适合它们的总宽度。这应该被考虑在内。

  3. 例如,最右边的div上的右边距应该用于计算,并应该增加容器的宽度。顶部,底部和最左边的div也是如此。

  4. 不需要IE8及以下版本。

  5. 请仅使用vanilla Javascript 。没有像jQuery等的框架。

  6. 谢谢!

    一些可视化: Type 1 (and 2) divs Type 3 divs

1 个答案:

答案 0 :(得分:1)

您可能必须自己进行性能测试,以确定哪种方法最快,但无论如何这里是一种非常快速的方法。 (jsfiddle

function getOuterBoxDimensions() {
    var original = document.getElementById('original'),
        divs = original.getElementsByTagName('div'),
        left = 0,
        right = original.offsetWidth,
        top = 0,
        bottom = original.offsetHeight;
    for (var i = 0, div; div = divs[i++];) {
        if (div.offsetTop < top) {
            top = div.offsetTop;
        }
        if (div.offsetTop + div.offsetHeight > bottom) {
            bottom = div.offsetTop + div.offsetHeight;
        }
        if (div.offsetLeft < left) {
            left = div.offsetLeft;
        }
        if (div.offsetLeft + div.offsetWidth > right) {
            right = div.offsetLeft + div.offsetWidth;
        }
    }
    return {
        top: top,
        left: left,
        bottom: bottom,
        right: right
    };
    // Note that dimensions are relative to the original div top left
}

据我所知,offsetLeft,offsetWidth等将返回正确的尺寸,无论是否设置了box-sizing: border-box。如果你在内部div中有div,那么事情会变得更复杂 - 你只想检查原始的childNodes的div。

编辑:这是一个扩展版本,它正确地考虑了边距并扩展了新容器以容纳单行中的所有浮动div(请参阅注释中的讨论)。 http://jsfiddle.net/m7N2J/10/

function getOuterBoxDimensions() {
    var original = document.getElementById('original'),
        divs = original.getElementsByTagName('div'),
        left = 0,
        right = original.offsetWidth,
        top = 0,
        bottom = original.offsetHeight,
        d = document.defaultView,
        style, marginTop, marginBottom, marginLeft, marginRight, float, floatWidth = 0;
    for (var i = 0, div; div = divs[i++];) {
        if (style = div.currentStyle) {
            // May be possible to exclude this if IE7/8 not needed
            marginTop = parseFloat(style.marginTop);
            marginBottom = parseFloat(style.marginBottom);
            marginLeft = parseFloat(style.marginLeft);
            marginRight = parseFloat(style.marginRight);
            float = style.float;
        }
        else {
            style = d.getComputedStyle(div, null);
            marginTop = parseFloat(style.getPropertyValue('margin-top'));
            marginBottom = parseFloat(style.getPropertyValue('margin-bottom'));
            marginLeft = parseFloat(style.getPropertyValue('margin-left'));
            marginRight = parseFloat(style.getPropertyValue('margin-right'));
            float = style.getPropertyValue('float');
        }
        if (float == 'left' || float == 'right') {
            floatWidth += div.offsetWidth + marginLeft + marginRight;
            if (div.offsetHeight + marginBottom > bottom) {
                bottom = div.offsetHeight + marginBottom;
            }
        }
        else {
            if (div.offsetTop - marginTop < top) {
                top = div.offsetTop - marginTop;
            }
            if (div.offsetTop + div.offsetHeight + marginBottom > bottom) {
                bottom = div.offsetTop + div.offsetHeight + marginBottom;
            }
            if (div.offsetLeft < left - marginLeft) {
                left = div.offsetLeft - marginLeft;
            }
            if (div.offsetLeft + div.offsetWidth + marginRight > right) {
                right = div.offsetLeft + div.offsetWidth + marginRight;
            }
        }
    }
    if (right < left + floatWidth) {
        right = left + floatWidth;
    }
    return {
        top: top,
        left: left,
        bottom: bottom,
        right: right
    };
    // Note that dimensions are relative to the original div
}