Appearance
04|CSS 盒模型与显示模式
CSS 把每个 HTML 元素都视为一个矩形盒子。理解这个盒子的构成——内容区、内边距、边框、外边距——是控制元素尺寸和间距的基础。两个元素为什么挨得太近或太远、设了宽度为什么实际占用空间更大,根子都在盒模型上。
一、盒模型的四个部分
一个元素在页面上占据的空间由四层组成:
┌─────────────────────────────┐
│ margin(外边距) │ ← 元素与其他元素的距离
│ ┌─────────────────────┐ │
│ │ border(边框) │ │ ← 边框线
│ │ ┌─────────────┐ │ │
│ │ │ padding(内边距)│ │ │ ← 内容与边框的距离
│ │ │ ┌─────┐ │ │ │
│ │ │ │content│ │ │ │ ← 实际内容区域
│ │ │ └─────┘ │ │ │
│ │ └─────────────┘ │ │
│ └─────────────────────┘ │
└─────────────────────────────┘用代码展示:
css
.box {
width: 200px; /* 内容区宽度 */
height: 100px; /* 内容区高度 */
padding: 20px; /* 内边距 */
border: 1px solid #ccc; /* 边框 */
margin: 10px; /* 外边距 */
}这个元素在页面上实际占用的水平空间是:
margin-left(10) + border-left(1) + padding-left(20) +
width(200) +
padding-right(20) + border-right(1) + margin-right(10) = 262px二、box-sizing
上面的计算方式(width 只指内容区)是 CSS 的默认行为,称为 content-box。但这种方式不直观:设了 width: 200px,实际宽度却受 padding 和 border 影响变成 262px。
box-sizing: border-box 改变了这个行为:
css
* {
box-sizing: border-box;
}
.box {
width: 200px;
padding: 20px;
border: 1px solid #ccc;
}此时 width: 200px 指的是内容区 + 内边距 + 边框的总宽度。内容区实际宽度自动计算为 200 - 20 - 1 - 20 - 1 = 158px。
| 值 | 含义 | width 包含 |
|---|---|---|
content-box | 默认值 | 仅内容区 |
border-box | 推荐值 | 内容区 + padding + border |
现代项目通常在全局重置中统一设置 border-box。这也是 CSS 框架(Bootstrap、Tailwind 等)的标准做法。
三、外边距折叠
垂直方向相邻的两个块级元素,它们的外边距不会相加,而是取较大值:
html
<style>
.a { margin-bottom: 20px; }
.b { margin-top: 30px; }
</style>
<div class="a">元素 A</div>
<div class="b">元素 B</div>A 和 B 之间的间距不是 20 + 30 = 50px,而是 30px(取较大值)。这个现象称为外边距折叠(margin collapsing)。
发生条件:
- 相邻兄弟元素之间
- 父元素的第一个/最后一个子元素与父元素的边界之间
- 空元素自身的上下外边距之间
阻止折叠的方法:
- 给其中一个元素加
padding或border - 给父元素创建 BFC(如
overflow: hidden) - 使用
flex或grid布局
四、display 属性
display 决定元素在页面上的显示模式。HTML 标签有默认的 display 值,但可以通过 CSS 修改。
block(块级)
css
div, p, h1, ul, li {
display: block;
}特性:
- 独占一行,前后产生换行
- 可以设置
width、height、margin、padding - 默认宽度填满父容器
inline(行内)
css
span, a, strong, em {
display: inline;
}特性:
- 不独占一行,与其他行内元素并排
- 不能设置
width和height(由内容决定) - 水平方向的
margin和padding有效,垂直方向不影响布局
css
/* 无效:inline 元素设宽高不会生效 */
span {
width: 100px;
height: 50px;
}inline-block(行内块)
css
.button {
display: inline-block;
width: 120px;
height: 40px;
line-height: 40px;
text-align: center;
}特性:
- 对外表现像
inline:不独占一行,可以与其他元素并排 - 对内表现像
block:可以设置width、height、margin、padding
适合需要并排显示但又需要控制尺寸的场景,如按钮、卡片缩略图。
none
css
.hidden {
display: none;
}元素从页面中完全移除,不占据任何空间。与 visibility: hidden 不同——后者隐藏元素但保留其占据的空间。
其他显示值
现代布局还会用到 flex、grid、table 等值,这些在专门的布局篇中详细讲。
五、宽度和高度计算
百分比宽度
css
.container {
width: 800px;
}
.sidebar {
width: 25%; /* 200px */
float: left;
}
.main {
width: 75%; /* 600px */
float: left;
}百分比基于父元素的内容区宽度计算。如果父元素有 padding 或 border,子元素的百分比不会自动扣除这些值——这就是 border-box 重要的原因。
最小/最大宽度
css
.card {
width: 100%;
min-width: 300px; /* 再窄也不能小于 300px */
max-width: 600px; /* 再宽也不能超过 600px */
}适合响应式设计:在小屏幕上不缩得太窄,在大屏幕上不拉得太宽。
height 的陷阱
css
.container {
height: 100%; /* 常常不生效 */
}百分比高度要求父元素有明确的高度。如果父元素高度由内容撑开(默认行为),height: 100% 无法计算。要让元素占满视口高度,用:
css
.full-height {
height: 100vh; /* vh = viewport height,100vh = 视口高度 */
}六、常见错误
忘记 box-sizing
css
/* 错误:实际宽度变成 242px,布局失控 */
.box {
width: 200px;
padding: 20px;
border: 1px solid #ccc;
}
/* 正确 */
.box {
box-sizing: border-box;
width: 200px;
padding: 20px;
border: 1px solid #ccc;
}inline 元素设垂直 margin
css
/* 无效:inline 元素的 margin-top/bottom 不影响布局 */
span {
display: inline;
margin-top: 20px;
}
/* 正确:改用 inline-block 或 block */
span {
display: inline-block;
margin-top: 20px;
}外边距折叠导致间距不符合预期
css
/* 期望间距 40px,实际只有 20px */
.header { margin-bottom: 20px; }
.content { margin-top: 20px; }
/* 解决:给 content 加上 padding-top 替代 margin-top */
.content { padding-top: 20px; }