CSS右边距在溢出滚动的Div内部不起作用

时间:2012-07-27 20:40:39

标签: html css scroll overflow margin

我正在尝试制作两个div,一个在另一个里面。内部div大于外部div,外部div具有overflow:scroll,内部div具有margin:25px。所以我这样做:

#outer {
    width: 200px;
    height: 100px;
    overflow: scroll;
}
#inner {
    width: 400px;
    height: 200px;
    margin: 25px;
}

...

<div id="outer">
    <div id="inner">

    </div>
</div>

而不是内部div具有25px的边缘,如预期的那样,三边有25px的边距,但在右边没有。在我看来,这非常违反直觉。

如果我添加一个宽度足够宽的中间div来包含内部div + 50px,我们可以让它看起来正确,但这看起来像是一个hacky解决方法。

请参阅我在JSFiddle上的示例:http://jsfiddle.net/d3Nhu/16/

在每个主流浏览器中都会出现相同的情况。这种行为有什么好的理由吗?根据CSS规范,这是正确的行为吗?

注意:正如您在此示例中所期望的那样,如果您使用overflow:auto而不是overflow:scroll,则没有任何区别。

编辑:请注意,我正在寻找此行为的解决方法。 (我已经找到了一个。)我正在寻找关于此行为的原因的任何见解,特别是如果它在CSS specification任何地方都有记录。

3 个答案:

答案 0 :(得分:47)

TL; DR:

边距用于从包装器移动元素,而不是向外扩展包装。

长篇解释:

此行为与在文档中的任何位置指定水平width之外的margin一致。要对其进行细分,请考虑以下代码段,其中我对没有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规范中记录的Visual格式化模型详细信息中。

摘自“Block-level, non-replaced elements in normal flow”的“Visual formatting model details”部分:

  

以下约束必须包含在其他属性的已使用值中:

     
    

'margin-left'+'border-left-width'+'padding-left'+'width'+'padding-right'+'border-right-width'+'margin-right'=包含的宽度块

  
     

[...]

     

如果以上所有都具有“auto”以外的计算值,则称这些值为“过度约束”,并且其中一个使用的值必须与其计算值不同。如果包含块的'direction'属性值为'ltr',则忽略指定的'margin-right'值,并计算该值以使等式为true。如果'direction'的值是'rtl',则会发生'margin-left'。

摘录非常密集,所以简单地说,让我们忽略borderpadding的宽度,两者都是0,留给我们width,{ {1}}和margin-left

现在,由于您有margin-rightwidth的固定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属性的CSS 2规范。

摘自“Overflow and clipping”的“Visual effects”部分:

  

每当发生溢出时,'overflow'属性指定是否将框剪切到其填充边缘,如果是,则是否提供滚动机制来访问任何剪切的内容。

看看它是如何具体说“剪掉内容”。有关“内容”的说明,请参阅CSS 2规范中的以下图表。

Box dimensions”的“Box model”部分中的图片:

box model

我们可以看到,overflowmargin是分开的。但是,在这一点上值得注意的是,滚动区域中包含填充和边框,因此当规范说“内容”时,它可能指的是边框,或者至少,它似乎是如何被解释的

为什么content有效?

基本上,display: inline-block元素的边距表现不同,因为它们是内容级别而不是块级别,并且它们没有“过度约束”的概念。

答案 1 :(得分:16)

display:inline-block;添加到#inner div

请参阅此fiddle

答案 2 :(得分:1)

因此,这里的答案实际上并不能解决问题! (尽管超级详细地说明了它不起作用的原因)

我需要一个解决方案。这是我将来的读者的地方。使用display:flex;与伪:: after元素的组合来伪造div的存在以提供所需的边距。

.wrapper {
  display: flex;
  width: 400px;
  height: 100%;
  padding: 40px;
  background: lightGrey;
}

.lists_container {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  overflow: auto;
  position: relative;
  background: grey;
  padding: 40px;
  margin: 40px;
  width: 100%;
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 250px;
  max-width: 500px;
  height: 100px;
  margin: 50px 0;
  padding: 20px;
  background: orange;
  margin-right: 30px;
}

.card.last::after {
  content: '';
  position: absolute;
  right: -100px;
  width: 40px;
  height: 100%;
  background: red;
}
<div class="wrapper">

  <div class="lists_container">

    <div class="card">
    </div>

    <div class="card">
    </div>

    <div class="card last">
    </div>

  </div>

</div>