CSS:浮动元素时边缘折叠问题的干净解决方案

Posted

技术标签:

【中文标题】CSS:浮动元素时边缘折叠问题的干净解决方案【英文标题】:CSS: clean solution to the margin collapse issue when floating an element 【发布时间】:2011-09-06 11:23:45 【问题描述】:

示例 html+CSS:

<html>
  <body style="padding: 0; margin: 0;">
    <div style="float: right;">first</div>
    <div style="margin-top: 2em;">second</div>
  </body>
</html>

期望的行为:first div 浮动到窗口的右上角。 实际行为:它在所需位置下方浮动 2em。 原因: margin collapsing.

尽管发现了问题,但我能想出的解决方案感觉就像是 hack:

body 样式更改为margin: -1px 0 0 0; border-top: 1px solid;。 在first 之前插入&lt;div style="height: 1px; margin-bottom: -1px;"&gt;&lt;/div&gt;firstsecond之间插入上面的&lt;div&gt;

有没有一种简洁、惯用的方法来避免这个问题?

【问题讨论】:

相关:clear and collapse fix. 【参考方案1】:

clear: right 添加到第二秒

<html>
  <body style="padding: 0; margin: 0;">
    <div style="float: right;">first</div>
    <div style="clear: right">second</div>
  </body>
</html>

【讨论】:

【参考方案2】:

解决方案

overflow: auto;overflow: hidden;overflow: scroll; 添加到htmlbody 标记。

如果你想知道为什么

body 标签上创建块格式化上下文(BFC)。

如果我只将overflow: hidden; 添加到body,为什么它不起作用?

原因如下:

W3C#block-formatting

浮动、绝对定位元素、不是块框的块容器(例如内联块、表格单元格和表格标题),以及具有“溢出”而不是“可见”的块框(除非该值已传播到视口)为其内容建立新的块格式化上下文。

W3C#overflow:

UA 必须将根元素上设置的“溢出”属性应用到视口。

当根元素是 HTML“HTML”元素或 XHTML“html”元素,并且该元素具有 HTML“BODY”元素或 XHTML“body”元素作为子元素时,用户代理必须改为应用 '如果根元素上的值为“可见”,则从第一个此类子元素到视口的溢出'属性。

用于视口的“可见”值必须解释为“自动”。

传播该值的元素必须具有用于“可见”的“溢出”的使用值

the first such child elementThe element from which the value is propagated 在这种情况下指的是body 标签。

换句话说,如果您将overflow: hidden;overflow: auto;overflow: scroll; 添加到bodyhtmloverflow 属性的值为visible,则body 的值s overflow 属性(hiddenautoscroll)将被传播到视口。所以根据 W3C 的第一个引用,body 不会建立新的块格式化上下文。

但是,如果将overflow: hidden;overflow: auto;overflow: scroll; 添加到html,则不会传播“body”的overflow 值,从而建立新的块格式化上下文。

【讨论】:

除了这个之外,没有其他答案可以解释为什么 body 上的溢出不会建立新的块格式化上下文,我认为这是问题的关键。【参考方案3】:

这可能很奇怪,但在新版本的 Chrome 和 Mozilla 中,您可以通过添加带边框的包装 div 来实现所需的行为(第一个 div 在右上角)

<html>
  <body style="padding: 0; margin: 0;">
    <div style="border: 1px solid black">
        <div style="float: right;">first</div>
        <div style="margin-top: 2em;">second</div>
    </div>
  </body>
</html>

【讨论】:

【参考方案4】:

overflow:hidden 不适合时可以使用的另一个技巧:

.clr:before, .clr:after 
    display: table;
    content: " ";
    clear: both;
    font-size: 0;

这个 sn-p 具有包含所有浮点数的副作用。

【讨论】:

font-size:0 并且现代浏览器不需要内容内的空格。在 IE10、Firefox 和 Chrome 上测试。 .clr:before,.clr:afterdisplay:table;content:"";clear:both 适用于 Firefox 3.5+、Safari 4+、Chrome、Opera 9+、IE 8+ ,根据nicolasgallagher.com/better-float-containment-in-ie【参考方案5】:

W3C 规范对折叠边距进行了描述:

“在本规范中,表达折叠边距是指两个或多个框(可能彼此相邻或嵌套)的相邻边距(没有非空内容、填充或边框区域或间隙分隔它们)合并形成一个边距。”

http://www.w3.org/TR/CSS21/box.html#collapsing-margins

处理折叠边距的最佳方法是在具有折叠边距的元素的顶部或底部填充中添加一个像素。

如果边缘在顶部折叠.. 那么:

#element-with-collapsed-margin 
   padding-top:1px;

border-top 也可以解决此问题

#element-with-collapsed-margin 
   border-top:1px solid transparent;

如果您的下边距折叠,那么您将添加 padding-bottom:1px;border-top:1px solid transparent;

基本上,顶部或底部的任何边框或填充都将阻止边距折叠,当您将它们放在彼此之上时,甚至当您有相互嵌套的元素时,边距折叠

很好的参考:

http://reference.sitepoint.com/css/collapsingmargins

..

【讨论】:

【参考方案6】:

在父 div 上添加此 #parent padding 1px 0; 这对我来说是一个大问题,我花了很长时间才找到解决方案。我在一个帖子上看到了 2 年,这解决了崩溃问题。

【讨论】:

【参考方案7】:

overflow: hidden; 添加到body 应该可以解决您的问题。它定义了一个新的块格式化上下文,如本文所述:The magic of overflow: hidden。

jsFiddle Demo(body 标签是 jsFiddle 自动添加的,所以我没有将它包含在 HTML 标记中)

更新(感谢@clairesuzy):如果bodypadding: 0,则此解决方案不起作用。在我找到更好的方法之前,我只能建议在两个 div 周围添加一个包装器(至少我现在应该得到@Marcel's downwote :)),我仍然认为这比 OP 发布的解决方案更干净。我通常会在浮动内容周围添加一个包装器(大多数时候更容易处理旧浏览器),大多数时候不需要故意添加它,因为它在逻辑和语义上都是必需的。

所以现在,我可以想出这个:

<body style="padding: 0; margin: 0;">
   <div id="container" style="overflow: hidden;">
       <div style="float: right;">first</div>
       <div style="margin-top: 2em;">second</div>
   </div>
</body>

jsFiddle Demo

更新 2:经过深思熟虑并阅读 cmets,我真的认为容器上的 overflow: hidden(或 overflow: visible 以外的任何内容)是正确的解决方案。它对我不起作用的唯一例外是将其设置在 body 元素上,无论如何这是一种非常罕见的情况。在这些罕见的情况下,您可以尝试使用position: absolute; top: 0; right: 0; 而不是浮动。

另一种可能的解决方法:我还发现在body 上设置display: inline-block; width: 100%; 确实有效。

jsFiddle Demo

【讨论】:

对不起,对我来说似乎不是一个“干净”的解决方案。它可以工作,但不是很实用,除非引入额外的元素。 @bazmegakapa 我真的认为这是答案,但它不起作用,实际的小提琴确实如此,但这只是因为 jsfiddle result-light.css 添加了一些主体填充(10px) - 并且正如我们所知,填充是折叠边距的“治疗”。1px 足以让它像@eegg 的边框顶部解决方案一样工作,似乎它确实需要一个额外的包装元素来应用溢出修复。 @bazmegakapa yours 是一个很好的答案,只是不适用于body 元素,这在现实世界的场景中是极不可能的。溢出隐藏在父元素上,即添加一个容器 div(除了body,它是根格式化上下文)将起作用。您不太可能希望浮动源中的第一个元素并且不希望它具有某种容器 div ;) 改变了我的投票。在“wrap”元素上设置overflow:hidden不仅是解决这个问题的好方法,而且可能已经普遍用于清除浮动。 我更喜欢overflow: auto 而不是overflow: hidden,因为您可能会在 div 内部产生一些应该在外部产生的效果(可能是相对定位的元素或伪元素,可能是一些盒子阴影)。事实上,visible 以外的任何其他值都应该有效。当然,如果宽度和高度不固定且小于内容,则两者都可以正常工作。【参考方案8】:

float: left; 添加到第二个div。

fiddle

【讨论】:

虽然它解决了问题,但在大多数情况下可能并不理想。

以上是关于CSS:浮动元素时边缘折叠问题的干净解决方案的主要内容,如果未能解决你的问题,请参考以下文章

css样式float造成的浮动“塌陷”问题的解决办法

通俗易懂的CSS的浮动float详解

CSS学习—浮动

CSS解决元素自定义顺序折叠问题

CSS浮动,BFC,清除浮动,高度塌陷以及最终解决方法

什么BFC?它解决了什么问题?