网页上每个元素都是一个矩形盒子:从里到外依次是内容、内边距 padding、边框 border、外边距 margin。理解盒模型,是排查"宽度怎么算不对"这类问题的关键。

四层结构

.box {
  width: 200px;        /* 内容宽度 */
  padding: 20px;       /* 内边距:内容与边框之间的留白 */
  border: 4px solid;   /* 边框 */
  margin: 16px;        /* 外边距:盒子与其他元素的距离 */
}

默认情况下(box-sizing: content-box),这个盒子实际占据的宽度是:

200(内容)+ 20×2(左右 padding)+ 4×2(左右 border)= 248px

也就是说 width 只描述内容区,多加一点 padding 页面就"撑爆"了。

box-sizing:改用更直观的计算方式

*,
*::before,
*::after {
  box-sizing: border-box;
}

改成 border-box 后,width 直接等于最终宽度,padding 和 border 向内挤压内容:无论 padding 和 border 怎么改,width: 200px 的盒子总宽度始终是 200px。

几乎所有现代项目都会在全局设置 border-box,强烈推荐。

margin 的两个经典行为

1. 外边距合并:上下相邻的两个块级元素,下方的 margin-top 和上方的 margin-bottom 会合并成一个,取较大的值,而不是相加。

/* A 的下边距 20px,B 的上边距 30px,实际间隔是 30px,不是 50px */
.a { margin-bottom: 20px; }
.b { margin-top: 30px; }

2. 父子 margin 传递:子元素的 margin-top 有时会"顶"到父元素外面,让父元素整体跟着下移。常见解法是给父元素加 overflow: hidden,或者改用 padding 实现内部留白。

margin 与 padding 怎么选

  • margin:控制盒子之间的距离,用在与"邻居"的关系上
  • padding:控制内容与自身边框的距离,属于盒子自己的一部分

一个实用判断:想让点击区域变大,用 padding;想拉开与相邻模块的距离,用 margin。

简写规则

margin 和 padding 都支持 1~4 个值的简写,规则一致(上 右 下 左,顺时针):

margin: 16px;               /* 四周相同 */
margin: 16px 24px;          /* 上下 16,左右 24 */
margin: 16px 24px 8px;      /* 上 16,左右 24,下 8 */
margin: 16px 24px 8px 32px; /* 上 右 下 左 */

顺带一提,定宽块级元素水平居中的经典写法也和 margin 有关:

.container {
  width: 960px;
  margin: 0 auto;   /* 上下 0,左右自动平分 */
}

小结

  • 默认盒模型的 width 只算内容区,全局改用 border-box 更省心
  • 相邻块级元素的上下 margin 会合并,取较大值
  • margin 管外部距离,padding 管内部留白
  • 简写按"上 右 下 左"顺时针记忆

盒模型是 CSS 排查问题的第一站:元素尺寸不符合预期时,先打开开发者工具的 computed 面板看一眼,八成能找到答案。