TL;DR:
边距用于将元素从包装器中移入,而不是向外扩展包装器。
长解释:
除了在文档中的任意位置指定水平margin 之外,此行为与指定width 一致。为了分解它,请考虑以下 sn-p,其中我指定了一个没有 overflow 属性的包装器,而 margin 不扩展包装器元素。
body {
padding: 20px;
}
.outer {
width: 400px;
border: 1px solid black;
}
.inner {
width: 400px;
height: 40px;
margin: 0 20px;
background: grey;
}
<div class="outer">
<div class="inner">
</div>
</div>
如您所见,margin 并没有导致包装器的大小扩大,元素只是继续溢出。此行为记录在 CSS 2.1 规范中的可视格式化模型详细信息中。
在其他属性的使用值中必须保持以下约束:
'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = 包含的宽度阻止
[...]
如果上述所有值都具有除“auto”之外的计算值,则这些值被称为“过度约束”,并且使用的值之一必须与其计算值不同。如果包含块的“direction”属性值为“ltr”,则忽略“margin-right”的指定值并计算该值以使等式成立。如果 'direction' 的值是 'rtl',这会发生在 'margin-left' 上。
这段摘录相当密集,所以简单来说,让我们忽略border 和padding 的宽度,它们都是0,剩下width、margin-left 和margin-right。
现在,由于您有一个固定的 width 和 margin-left 和 margin-right 的值,因此这些值“过度约束”。现在在我们的例子中,由于默认方向是ltr,所以margin-right被强制补偿。
要查看方向的效果,让我们尝试将dir="rtl" 属性添加到包装元素。
body {
padding: 20px;
}
.outer {
width: 400px;
border: 1px solid black;
}
.inner {
width: 400px;
height: 40px;
margin: 0 20px;
background: grey;
}
<div class="outer" dir="rtl">
<div class="inner">
</div>
</div>
现在元素向左溢出。让我们看看这个dir="rtl" 属性是否对您的overflow: scroll 示例具有相同的效果。
#outer {
border: 1px solid #00F;
width: 200px;
height: 100px;
overflow: scroll;
}
#inner {
border: 1px solid #F0F;
margin: 25px;
width: 400px;
height: 200px;
}
<div id="outer" dir="rtl">
<div id="inner">
</div>
</div>
是的,确实如此。现在左边的边距不见了,而不是右边。
但为什么overflow: scroll 不包括边距?
主要是因为规范没有说应该。让我们看一下 overflow 属性的 CSS 2 规范。
每当发生溢出时,'overflow' 属性指定一个框是否被剪裁到其填充边缘,如果是,是否提供滚动机制来访问任何被剪裁的内容。
看看它是如何具体说“剪辑的内容”的。关于“内容”的解释,请参考 CSS 2 规范中的下图。
正如我们所见,margin 与 content 是分开的。然而,此时值得注意的是,填充和边框包含在滚动区域中,所以当规范说“内容”时,它可能指的是边框框,或者至少,它似乎是这样解释的。
为什么display: inline-block 有效?
基本上,inline-block 元素的边距表现不同,因为它们是内容级别而不是块级别,并且它们没有“过度约束”的概念。