假设我们有一个未知width
和height
的容器div,它小于身体的整个尺寸。
此容器div包含未知数量的div。容器中的所有div都具有不同大小,除此之外,它们具有与以下3种类型之一相同的CSS:
类型1和2 div具有边距,可能也有填充。类型3 div可以有,也可以两者都没有。
鉴于容器中div的类型未知 - 最终目标是在原始内部添加一个辅助容器,其大小足以容纳视口中的所有div(带溢出:滚动)。 最便宜的计算方法是什么?
要记住的一些事情:
div 可能<也不是(整体而言)box-sizing: border-box
。这将影响它们的边框,边距和填充的呈现方式,也应该考虑在内。
在类型1和类型2(浮动div)的情况下,div意味着水平堆叠 - 即,容器应该增长以适合它们的总宽度。这应该被考虑在内。
例如,最右边的div上的右边距应该用于计算,并应该增加容器的宽度。顶部,底部和最左边的div也是如此。
不需要IE8及以下版本。
请仅使用vanilla Javascript 。没有像jQuery等的框架。
谢谢!
一些可视化:
答案 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
}