CSS盒模型详解
# 02.CSS盒模型详解
从 content-box 到 border-box,掌握 margin 塌陷、BFC 块级格式化上下文、display 两大布局体系,彻底理解 CSS 布局的底层基石。
# 1. 两种盒模型
浏览器的渲染引擎把每个元素看作一个矩形盒子,由四层组成:
┌─────────────────────────────────────┐
│ margin │ ← 外边距(透明,不计入元素尺寸)
│ ┌───────────────────────────────┐ │
│ │ border │ │ ← 边框
│ │ ┌─────────────────────────┐ │ │
│ │ │ padding │ │ │ ← 内边距
│ │ │ ┌───────────────────┐ │ │ │
│ │ │ │ content │ │ │ │ ← 内容区
│ │ │ └───────────────────┘ │ │ │
│ │ └─────────────────────────┘ │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
# 1.1 content-box(标准盒模型,默认)
.box { box-sizing: content-box; }
width/height 只包含 content 区域:
div {
box-sizing: content-box;
width: 200px; /* 仅内容宽度 */
padding: 20px; /* + 左右各 20 = 40 */
border: 5px solid; /* + 左右各 5 = 10 */
}
/* 实际占据宽度 = 200 + 40 + 10 = 250px */
/* 实际占据高度 = height + padding-top-bottom + border-top-bottom */
# 1.2 border-box(IE 盒模型,推荐)
.box { box-sizing: border-box; }
width/height 包含 content + padding + border:
div {
box-sizing: border-box;
width: 200px; /* content + padding + border 总共 200 */
padding: 20px; /* 内容区自动缩小为 200 - 40 - 10 = 150 */
border: 5px solid;
}
/* 实际占据宽度 = 200px(不会再膨胀) */
全局设置(几乎所有项目的第一条 CSS 规则):
*, *::before, *::after {
box-sizing: border-box;
}
实战对比:
/* content-box 下设置 50% 宽度 + padding → 必然溢出 */
.col {
box-sizing: content-box;
width: 50%;
padding: 0 10px;
}
/* 两列总宽度 = 50%×2 + 20px×2 > 100% → 换行 */
/* border-box 下安全 */
.col {
box-sizing: border-box;
width: 50%;
padding: 0 10px;
}
/* 两列刚好 100% */
# 2. display 两大布局体系
display 决定了元素在文档流中的行为。它有两个维度:
display 分类树:
┌─ 外部表现(决定元素在文档流中的角色)
│ ├── block → 独占一行,可设宽高
│ ├── inline → 行内排列,不可设宽高
│ └── inline-block → 行内排列,可设宽高
│
└─ 内部布局(决定子元素的排列方式)
├── flow / flow-root → 正常文档流 / BFC
├── flex → 弹性布局
├── grid → 网格布局
└── table / none → 表格 / 隐藏
# 2.1 block / inline / inline-block
| 特性 | block | inline | inline-block |
|---|---|---|---|
| 独占一行 | ✅ | ❌ | ❌ |
| 可设 width/height | ✅ | ❌ | ✅ |
| 可设 margin/padding(上下) | ✅ | ❌(上下无效) | ✅ |
| 默认宽度 | 100% 父容器 | 内容宽度 | 内容宽度 |
| 典型元素 | div, p, h1-h6, section | span, a, strong | button, input |
/* inline 元素的 margin-top/bottom 无效 */
span { margin-top: 20px; } /* 不生效 */
/* inline 的 padding-top/bottom 不占空间(视觉有效但不影响布局) */
span { padding: 20px; } /* 文字背景变大但不推开上下元素 */
# 2.2 隐藏元素的三种方式
| 方式 | 占位 | 事件响应 | DOM 存在 |
|---|---|---|---|
display: none | ❌ 不占 | ❌ | ✅ |
visibility: hidden | ✅ 占位 | ❌ | ✅ |
opacity: 0 | ✅ 占位 | ✅ | ✅ |
.hide1 { display: none; } /* 完全移除,后续元素顶上 */
.hide2 { visibility: hidden; } /* 保留空间,只是看不见 */
.hide3 { opacity: 0; } /* 保留空间,可点击 */
# 3. margin 塌陷与合并
# 3.1 父子 margin 塌陷
父元素的第一个/最后一个子元素的 margin-top/bottom 会穿透父元素:
<style>
.parent { background: #eee; /* 没有 border/padding */ }
.child { margin-top: 50px; }
</style>
<div class="parent">
<div class="child">我是子元素</div>
</div>
<!-- .parent 会被 .child 的 margin-top 推下来,而不是 .child 在 .parent 内部偏移 -->
四种阻止方案:
.parent {
/* 方案 1:加透明边框 */
border-top: 1px solid transparent;
/* 方案 2:加内边距(最常用) */
padding-top: 1px;
/* 方案 3:触发 BFC(见下节) */
overflow: hidden;
/* 方案 4:用 flex/grid 代替 */
display: flex;
}
# 3.2 兄弟 margin 合并
相邻兄弟元素的上下 margin 会合并(取较大值):
.top { margin-bottom: 30px; }
.bottom { margin-top: 20px; }
/* 两者间距 = max(30, 20) = 30px,不是 30+20=50px */
margin 合并规则:
均为正值 → 取最大值
一正一负 → 相加
均为负值 → 取最小值(绝对值最大)
阻止兄弟合并:触发 BFC(如 display: flex)、inline-block。
# 4. BFC(Block Formatting Context)
BFC 是一个独立的渲染区域,内部元素的布局不会影响外部。
# 4.1 BFC 的触发条件
/* 以下任一都能触发 BFC */
.bfc {
overflow: hidden; /* 最常用,非 visible */
display: flow-root; /* 最语义化,仅触发 BFC */
display: flex; /* flex/grid 容器自动是 BFC */
float: left; /* 非 none */
position: absolute; /* absolute/fixed */
/* contain: layout | paint 也能触发 */
}
# 4.2 BFC 解决的实际问题
① 清除浮动(经典用法)
/* 父元素包裹浮动子元素 */
.container { overflow: hidden; } /* 触发 BFC,自动清除浮动 */
② 阻止 margin 塌陷
.parent { overflow: hidden; } /* BFC 父元素 → 子 margin 不穿透 */
③ 自适应两栏布局
.left { float: left; width: 200px; }
.right { overflow: hidden; } /* BFC 元素不与浮动重叠 */
# 5. 实战:盒模型调试
/* 开发阶段给所有元素加边框,直观看到盒模型 */
* { outline: 1px solid rgba(255,0,0,0.2); }
DevTools 盒模型面板:F12 → Elements → 选中元素 → Styles 面板底部,实时显示 content / padding / border / margin 四层数值。
# 速查表
| 问题 | 解法 |
|---|---|
| 子元素 margin-top 把父元素推下去 | 父元素 padding-top: 1px 或 overflow: hidden |
| 兄弟元素 margin 间距不对 | 只设一个方向的 margin(如统一用 margin-bottom) |
| 宽度 50% + padding 导致换行 | 全局 box-sizing: border-box |
| 父元素高度塌陷(子元素浮动) | 父元素 overflow: hidden |
| 浮动元素遮挡普通流元素 | 被遮挡元素触发 BFC:overflow: hidden |
下一篇:03.Flex弹性布局 — 现代 CSS 布局第一利器,从主轴/交叉轴到 Flex+Grid 混合布局。
上次更新: 2026/06/24, 10:13:05