[译][CSS]如何处理边距坍塌?

[译]如何处理边距坍塌?

margin collapsing 会被翻译为边界坍塌,边界崩塌,外边距重叠,边界折叠,边距重合...。 边距坍塌是表象,外边距重叠从理论上描述着这种现象发生的原因,坍塌是因为重叠了。

css盒子模型

在我们探讨外边距坍塌如何工作之前,我们需要重新研究盒子模型,文档树中的每个元素都是一个矩形框,由四个区域组成:内容区(content area),填充区域(padding area),边框区域(border area)和边距区域(margin area)。

外边距区域是元素边框外面的空白,我们看下.box元素示例:

.box {
  width: 300px;
  height: 300px;
  padding: 50px;
  border: 50px solid grey; 
  margin: 50px; /* margin area */
}

下图条纹区域为外边距区域的空白,如下所示:

外边距区域与盒模型的其他三个区域不同,因为在技术上它不是元素本身的一部分。即使我们在CSS中为元素指定设置了外边距(margin),在文档上绘制的实际边界也会受到文档中其他元素的影响,就像我们在外边距重叠看到的情况一样。

什么是外边距重叠?

当两个块元素在垂直方向相邻时,将2个边距的较大者(或相等的任意一个)假定为单个折叠边距。

我们有2个元素,元素A为下边距为10px,元素B的上边距为30px,分开展示效果如下:

如果我们把2个元素垂直方向依次放置这2个块元素,结果如下:

元素A和元素B的外边距会合并到一起,保留了30px的外边距。

什么时候会外边距重叠

普遍的规则是:正常文档流中2个块级元素的垂直外边距始终会重叠,有以下四种情况:

情况1:父元素和其第一个子元素的上边距

父元素上边距和第一个子元素的上边距会发生重叠。

.parent {
  margin-top: 30px;
  height: 150px;
  background-color: rgb(200,200,200); /* Grey */
}

.child {
  margin-top: 30px;
  width: 100px;
  height: 100px;
  background-color: rgb(250, 219, 92); /* Yellow */
}

情况2:父元素和其最后一个子元素的下外边距

和上一个示例类似,如果父元素和子元素的最后一个都存在下外边距(margin-bottom),下外边距可能会重叠。但是,与上外边距不同,仅在父元素的高度是auto时,下边距才有重叠。

.parent {
  margin-bottom: 30px;
  height: auto;
  background-color: rgb(200,200,200);
}

.child {
  margin-bottom: 30px;
  width: 100px;
  height: 100px;
  background-color: rgb(250, 219, 92);
}

情况3:相邻块元素的垂直外边距

有2个元素,元素A有底边外边距,元素B流入元素B底部,则这2个块元素可能会垂直外边距重叠。

.sibling-one {
  margin-bottom: 10px;
  width: 100px;
  height: 100px;
  background-color: rgb(250, 219, 92);
}

.sibling-two {
  margin-top: 30px;
  width: 100px;
  height: 100px;
  background-color: rgb(200,200,200);
}

情况4:空元素

最后一种情况,如果这个元素的计算高度是0或者是一个空元素,元素的上外边距(margin-top)和其下外边距(margin-bottom)可能会重叠,即元素自身垂直外边距重叠。

<p>This paragraph is before the empty element</p>
<div class="empty"><!-- 空元素 --></div>
<p>This paragraph is after the empty element</p>

例外

有一些例外情况,垂直外边距不会重叠,我们需要了解这些例外情况。

Flexbox,Grid和其他非块级元素

外边距重叠只适用于块级元素,如果块元素的display属性设置为以下任一值

  • block
  • list-item
  • table

因此,弹性项目(flex items),网格项目(grid items),绝对定位项目(absuolute,fixed)和其非块级元素不适用。

根元素

可以理解为body永远不会和子元素的垂直外边距重叠。

线框,间隙,填充,和边框

  • 间隙:父子元素,兄弟元素之间有元素把他们隔离开。
  • 填充:父子元素父元素设置padding。
  • 边框:元素有一个设置了边框。

存在以上情况,则不会发生父子兄弟元素垂直外边距重叠。

如情况1示例,父元素的上边距和子元素的上边距重叠,我们给父元素设置边框则外边距不会重叠。

发生这种情况是因为父元素的边缘不再与子元素的边缘直接接触

处理外边距重叠

如果您不正确地了解可折叠边距的发生时间,则可能会很痛苦。 处理或避免它们的第一步是准确了解我们正在处理哪种情况的可折叠边距。

真正无法避免由于元素为空或父子关系而导致的边距重叠。 抵消这种可折叠边距的唯一方法是在元素之间插入一些东西,例如边框。 否则,可以将元素的显示状态更改为非块级。

另一方面,可以通过更改CSS书写样式来避免由于相邻的同级元素而导致的边距崩溃。 目前比较推崇的是哈里·罗伯茨(Harry Roberts)的Single-direction margin declarations单向保证金声明规则,该规则除了有助于避免可折叠的保证金之外,还有其他好处。

Single-direction margin declarations单向保证金声明规则: 其实就是避免给块元素同时设置上下外边距,使用单向原则,垂直方向只设置一个方向的外边距(margin-bottom)

  • 能轻松定义垂直方向的元素
  • 如果边距都使用一个规则margin-bottom,如果我添加,移动或删除一个元素,我的间距不会弄乱。
  • 如果组件和元素的边距不取决于相邻的元素,则它们不一定必须按一定的顺序存在。

本文使用 mdnice 排版

posted @ 2020-07-08 09:54  大圣巴巴  阅读(13)  评论(0编辑  收藏