核心概念
每个 HTML 元素的盒子由 4 个部分组成(从内到外):
- 内容区(content) :元素的实际内容(文字 / 图片等),对应
width/height属性; - 内边距(padding) :内容区和边框之间的空白,不会显示背景色 / 背景图(但会继承元素背景);
- 边框(border) :包裹内边距和内容的线条,可设置宽度、样式、颜色;
- 外边距(margin) :盒子与其他盒子之间的空白,完全透明,不会影响盒子自身尺寸。
- 边框与轮廓的区别:
- 边框(border):占据布局空间,会影响元素的总尺寸。
- 轮廓(outline):不占据布局空间,绘制在边框之外,常用于焦点状态提示。
box-sizing
外边距折叠
-
适用场景:
- 并列关系(兄弟) :上下相邻的块级元素,其下外边距与上外边距会发生合并。
- 嵌套关系(父子) :父元素与子元素无内边距 / 边框隔断时,各自的上 / 下外边距会发生合并(该场景也被称为「外边距塌陷」)。
- 空元素自合并:空块级元素(无内容、无 border、无 padding),其自身的上外边距与下外边距会发生合并,且可继续与相邻元素外边距合并。
-
合并规则: 多个垂直外边距相遇时,会合并为一个外边距,其大小等于所有参与合并的外边距中的最大值;若包含负边距,则按以下规则计算:
- 一正一负:最终间距 = 正边距 - 负边距的绝对值
- 两个负边距:最终间距 = 绝对值更大的那个负值
-
示例 1:兄弟元素合并
- A 盒子设置
margin-bottom: 100px - B 盒子设置
margin-top: 50px - 合并后,两盒之间的实际间距为 100px,而非 150px。
- A 盒子设置
-
示例 2:父子元素塌陷(合并)
- 父元素设置
margin-top: 20px - 子元素设置
margin-top: 10px - 合并后,整体表现为父元素的
margin-top: 20px,子元素的外边距 “穿透” 到父元素外部(即外边距塌陷)。
- 父元素设置
-
示例 3:空元素自合并
- 空元素设置
margin-top: 150px+margin-bottom: 150px - 合并后,实际只表现为 150px 的外边距;若与其他元素相邻,会继续参与合并。
- 空元素设置
-
设计意义: 外边距合并是浏览器为保证排版一致性的设计,以段落文本为例,合并后段落之间的间距与页面顶部间距保持一致,避免出现 “段落间距是顶部两倍” 的不均匀效果。
-
开发建议: 这是浏览器的固有特性,在布局时只需为其中一个元素设置所需的垂直外边距即可,避免重复设置导致预期混乱;若需彻底避免,可通过触发 BFC 实现。
-
完整代码示例(包含兄弟 / 父子 / 空元素合并) :
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>外边距折叠 完整示例</title>
<style>
/* 兄弟元素合并 */
.box-a {
width: 200px;
height: 100px;
background: #ff6347;
margin-bottom: 100px;
}
.box-b {
width: 200px;
height: 100px;
background: #4169e1;
margin-top: 50px;
}
/* 父子元素塌陷(合并) */
.parent {
width: 300px;
background: #f0e68c;
margin-top: 20px;
}
.child {
width: 150px;
height: 150px;
background: #ff6347;
margin-top: 10px; /* 与父元素margin-top合并,触发塌陷 */
}
/* 空元素自合并 */
.empty {
margin-top: 150px;
margin-bottom: 150px;
}
</style>
</head>
<body>
<!-- 兄弟元素合并 -->
<div class="box-a">A盒子(margin-bottom: 100px)</div>
<div class="box-b">B盒子(margin-top: 50px)</div>
<hr>
<!-- 父子元素塌陷(合并) -->
<div class="parent">
<div class="child">子盒子(margin-top: 10px)</div>
</div>
<hr>
<!-- 空元素自合并 -->
<div class="box-a">上盒子</div>
<div class="empty"></div> <!-- 空元素,上下margin合并为150px,遇到其他元素相邻,会继续参与合并,如上边有个margin-bottom为100px的盒子,再次合并为150px -->
<div style="width:150px;height:150px;background-color:pink;">下盒子</div>
</body>
</html>
外边距塌陷
margin-top 塌陷
-
适用场景:嵌套关系(父子)的块级元素,子元素设置
margin-top时,会导致父盒子整体向下移动。 -
本质原因:父元素与子元素的
margin-top发生合并,子元素的margin-top“穿透” 到父元素外部,表现为父盒子整体位移。 -
具体表现:
- 预期:子盒子在父盒子内向下偏移 50px
- 实际:父盒子整体向下偏移 50px,子盒子在父盒子内仍紧贴顶部
-
触发条件:
- 父元素无
border-top/padding-top(无物理隔断) - 父元素未触发 BFC(无
overflow: hidden/float/position: absolute等) - 子元素为块级元素,且设置了
margin-top
- 父元素无
-
代码示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>margin-top 塌陷</title>
<style>
.parent-top {
width: 300px;
height: 300px;
background: #f0e68c;
/* 无 border/padding/overflow,满足塌陷条件 */
}
.child-top {
width: 150px;
height: 150px;
background: #ff6347;
margin-top: 50px; /* 触发 top 塌陷 */
}
</style>
</head>
<body>
<div class="parent-top">
<div class="child-top">子盒子(top 塌陷)</div>
</div>
</body>
</html>
margin-bottom 塌陷
-
适用场景:嵌套关系(父子)的块级元素,子元素设置
margin-bottom时,会导致父盒子高度未包含该外边距,且该外边距作用于父盒子与外部元素的间距。 -
本质原因:父元素与子元素的
margin-bottom发生合并,子元素的margin-bottom“穿透” 到父元素外部,表现为父盒子高度未被撑开、间距外移。 -
具体表现:
- 预期:父盒子高度 = 子盒子高度 + 子盒子
margin-bottom(150px + 50px = 200px) - 实际:父盒子高度 = 子盒子高度(150px),
margin-bottom作用于父盒子与下方元素的间距
- 预期:父盒子高度 = 子盒子高度 + 子盒子
-
触发条件:
- 父元素无
border-bottom/padding-bottom(无物理隔断) - 父元素未触发 BFC(无
overflow: hidden/float/position: absolute等) - 父元素高度由内容撑开,且内部仅包含该子元素
- 子元素为块级元素,且设置了
margin-bottom
- 父元素无
-
代码示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>margin-bottom 塌陷</title>
<style>
.parent-bottom {
width: 300px;
background: #f0e68c;
/* 无 height/border/padding/overflow,满足塌陷条件 */
}
.child-bottom {
width: 150px;
height: 150px;
background: #ff6347;
margin-bottom: 50px; /* 触发 bottom 塌陷 */
}
.rel {
width: 150px;
height: 150px;
background: pink; /* 参考块,用于观察塌陷间距 */
}
</style>
</head>
<body>
<div class="parent-bottom">
<div class="child-bottom">子盒子(bottom 塌陷)</div>
</div>
<div class="rel">参考块</div>
</body>
</html>
通用解决方案
- 物理隔断:给父盒子添加对应方向的边框(如
border-top/border-bottom),物理上隔开父子元素的外边距。 - 缓冲层:给父盒子添加对应方向的内边距(如
padding-top/padding-bottom),原理与添加边框类似。 - 触发 BFC(推荐) :给父盒子添加
overflow: hidden;属性,触发 BFC(块级格式化上下文),阻止外边距合并。
- 修复代码示例:
/* 以 margin-top 塌陷为例,bottom 塌陷修复方式一致 */
.parent-top {
width: 300px;
height: 300px;
background: #f0e68c;
overflow: hidden; /* 触发 BFC,修复塌陷 */
}
核心注意点
- 仅垂直方向生效:水平方向的
margin-left/margin-right永远不会发生折叠 / 塌陷。 - 仅普通文档流块级元素生效:行内元素、浮动元素、绝对定位元素、Flex/Grid 子元素的外边距不会合并。
- 空元素自合并:空块级元素的上下外边距会合并,若与其他元素相邻,会继续参与合并,这是段落元素占用空间较小的原因。
- 实战修复优先用 BFC:
overflow: hidden(或display: flow-root)是无视觉副作用的最优修复方案,避免 border/padding 带来的尺寸干扰。
最终总结
外边距合并(折叠)是普通文档流中块级元素垂直外边距的合并行为,「外边距塌陷」是父子嵌套场景下的特殊合并表现,核心规则是「合并后取最大外边距」,其设计目的是保证排版均匀,实战中通过触发 BFC 即可彻底避免。