每个盒子的四层
页面上的每个元素都被画成一个矩形,由内到外分为四层:
- 内容:文字、图片或子元素,大小由
width和height决定。 - 内边距(padding):盒子内部、内容与边框之间的空间。这里会显示元素的背景。
- 边框(border):包围内边距的线。
- 外边距(margin):边框之外的空间,用来把其他盒子推开。始终是透明的。
在这个例子中,每一层都有自己的颜色:蓝色是内容,绿色是内边距,深色是边框,盒子周围的琥珀色区域是外边距(由一个外层元素画出来,因为外边距本身是透明的)。
盒子下方那一行是浏览器测量出的结果:160 + 20 + 20 + 10 + 10 = 220px。外边距会在两侧各再加 24px,但它在盒子之外,所以不计入这 220px。
宽度计算:content-box 与 border-box
默认情况下(box-sizing: content-box),width 只设置内容的宽度。内边距和边框会额外加上去,所以盒子最终比你写的数字更宽。使用 box-sizing: border-box 时,width 就是整个盒子的宽度,内容会缩小,为内边距和边框腾出空间。
content-box(默认值) | border-box | |
|---|---|---|
width 指的是 | 内容 | 内容 + 内边距 + 边框 |
width: 200px; padding: 20px; border: 5px | 宽 250px | 宽 200px |
| 此时的内容区域 | 200px | 150px |
| 外边距 | 在外面,不计入 | 在外面,不计入 |
border-box 重置
因为 border-box 让尺寸计算更直观,几乎所有现代样式表都以这条规则开头:
*,
*::before,
*::after {
box-sizing: border-box;
}
它在使用百分比时最重要。在 content-box 下,两个带内边距的 width: 50% 列放不进同一行,因为每一列都是 50% 再加上它的内边距:
(HTML 注释去掉了 inline-block 列之间的空格,否则这些空格会额外占用几个像素。)
在开发者工具中查看盒模型
每个浏览器都会帮你画出盒模型。右键点击一个元素,选择“检查”,打开“计算样式”标签页(Firefox 中是“布局”):图示中间显示内容的尺寸,四周依次是内边距、边框和外边距的值。在元素面板中把鼠标悬停在某个元素上,页面也会着色:内容为蓝色,内边距为绿色,外边距为橙色。
行内盒子遵循不同的规则
上面介绍的盒模型描述的是 <div> 和 <p> 这样的块级盒子。<span>、<a> 和 <strong> 这样的行内元素在一行文字中换行排列,对垂直空间的处理方式也不同:
| 属性 | 在行内元素上的表现 |
|---|---|
width、height | 被忽略 |
| 水平方向的内边距、边框、外边距 | 生效,并把相邻内容向两侧推开 |
| 垂直方向的内边距和边框 | 会画出来,但不会推开上下的行 |
| 垂直方向的外边距 | 被忽略 |
display: inline-block 让行内的元素拥有完整的盒模型:它的宽度、高度、内边距和外边距都会占用空间。每一层的详细介绍见 CSS 内边距和 CSS 外边距。
常见错误
- 给固定宽度的盒子加了内边距,却不明白它为什么变大了。 在
content-box下,内边距和边框会加到width上。请使用border-box。 - 以为外边距会显示背景颜色。 外边距始终是透明的;需要有颜色的空白时,请使用内边距。
- 给行内元素设置
height或垂直外边距。 不会有任何效果;请使用display: inline-block或block。 - 计算时忘了边框。 在
content-box下,给width: 100%的元素加上 1px 边框,它就会宽出 2px,可能导致出现水平滚动条。 - 混淆外边距和内边距。 简单来说:内边距在边框里面,外边距在边框外面。margin 与 padding 页面把两者放在一起做了对比。
常见问题
CSS 盒模型是什么?
它是这样一条规则:每个元素都渲染为一个由四层组成的矩形盒子,分别是内容、包围内容的内边距、包围内边距的边框,以及边框之外的外边距。CSS 中的宽度、高度和间距都设置在这些层上。
box-sizing: border-box 有什么作用?
它让 width 和 height 包含内边距和边框。一个 width: 200px、padding: 20px、边框 5px 的盒子,宽度就正好是 200px,内容区域会缩小到 150px 来适应。默认值 content-box 则会把内边距和边框额外加上去,得到 250px。
元素的总宽度是怎么计算的?
使用默认的 content-box 时:width + 左右内边距 + 左右边框。使用 border-box 时:就是 width。两种情况下外边距都在盒子之外,所以它增加的是元素占据的空间,而不是元素本身的宽度。
外边距属于盒模型吗?
属于,它是最外面的一层,但它始终是透明的,也从不计入元素自身的宽度或背景。它只负责把相邻的盒子推开。
应该给所有元素都设置 box-sizing: border-box 吗?
大多数项目都会这样做,在样式表开头写上 *, *::before, *::after { box-sizing: border-box; }。这样百分比宽度和内边距加起来的结果就符合人们的预期,Bootstrap 和 Tailwind 等框架也自带同样的重置规则。