CSS 右边距在溢出滚动的 div 中不起作用

Posted

技术标签:

【中文标题】CSS 右边距在溢出滚动的 div 中不起作用【英文标题】:CSS Right Margin Does Not Work Inside a Div With Overflow Scroll 【发布时间】:2012-07-26 13:51:53 【问题描述】:

我正在尝试制作两个 div,一个在另一个里面。内层div大于外层,外层有overflow:scroll,内层有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 任何地方。

【问题讨论】:

brunildo.org/test/scroll-child-margin.html有一个很好的问题演示 【参考方案1】:

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 规范中的可视格式化模型详细信息中。

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

在其他属性的使用值中必须保持以下约束:

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

[...]

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

这段摘录相当密集,所以简单来说,让我们忽略borderpadding 的宽度,它们都是0,剩下widthmargin-leftmargin-right

现在,由于您有一个固定的 widthmargin-leftmargin-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 规范。

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

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

看看它是如何具体说“剪辑的内容”的。关于“内容”的解释,请参考 CSS 2 规范中的下图。

来自“Box model”的“Box dimensions”部分的图形:

正如我们所见,margincontent 是分开的。然而,此时值得注意的是,填充和边框包含在滚动区域中,所以当规范说“内容”时,它可能指的是边框框,或者至少,它似乎是这样解释的。

为什么display: inline-block 有效?

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

【讨论】:

【参考方案2】:

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

看到这个fiddle

【讨论】:

您能否解释一下为什么 div 必须是 inline-block 元素才能使右边距推出外部 div? 它与依赖于空白的渲染有关,除此之外我不太确定。 designshack.net/articles/css/… 有一个很好的参考资料 感谢您的参考。仍然不是我所期望的,但这确实有些道理。 应该指出,如果您有依赖于 width:auto 的内部内容的 css,这不是一个好的解决方法。像 jQuery UI 的选项卡这样的东西不会再填满整个 div,因为它没有已知的父宽度。【参考方案3】:

所以这里的答案实际上并不能解决问题! (虽然对它不起作用的原因非常详细)

我需要一个解决方案。这是我的未来读者。使用 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>

【讨论】:

如果您可以简化 CSS 以去除不相关的部分(例如 border-radius),那就太好了,但是 +1 可以找到现代的 flexbox 解决方案! 当然,@SeantheBean 清理了一点。也可以随意编辑。我正在快速复制我自己的代码!对 flexbox 的热爱!

以上是关于CSS 右边距在溢出滚动的 div 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

Div 的边距在 Internet Explorer 中不起作用

特定断点处元素的边距在 Tailwind 中不起作用

溢出:覆盖在 Firefox 中不起作用

fpdf设置页边距在python中不起作用

溢出:自动在 Firefox 中不起作用

将溢出设置为在固定 div 上滚动不起作用