每个元素都是一个矩形盒子:内容 + 内边距 + 边框 + 外边距

从内到外四层。width 只描述哪一层,取决于 box-sizing;margin 在盒子外面,不属于盒子本身但参与布局占位。

content-box 与 border-box:同一段 CSS,两种占位

content-box(默认)
占位 = 160 + 16×2 + 4×2 = 200px
border-box
占位 = 160px,padding/border 从 160 里扣
/* 现代项目第一行就写这个,全站统一 */
*, *::before, *::after { box-sizing: border-box; }

为什么它更好用:width: 100% 加个内边距不会溢出父容器;算栅格列宽时不用再减 padding。代价是 width 不再等于内容宽,需要用 min-width 保内容下限。

外边距塌陷(margin collapsing):16 + 16 ≠ 32

上/下 margin 各 16px

两个相邻块级元素之间的实际间距 = 较大那个,不是相加

现象规则
兄弟之间相邻的垂直 margin 合并为最大值(正+正取大;负+负取绝对值大;正+负相加)
父与首个子父元素没有 padding-top/border-top 时,子的 margin-top 会「穿透」到父身上,把整个父往下推
谁不塌陷flex/grid 容器的子项、float、绝对定位、inline-block、overflow 非 visible 的 BFC 容器

这就是为什么老布局里到处都是「加个 overflow: hidden」的玄学修复——它在创建 BFC。今天用 Flex 的 gap 可以从根上绕开塌陷,不必理解合并规则也能排好间距。

父边距塌陷现场

子元素 margin-top: 24px —— 绿色父容器整体被推下去了,父与子之间并没有 24px 白缝

负 margin:合法的「往回拽」

正常 margin-left: 60px
同一列里用更小的 margin 制造错位(也可写 margin-left: -24px 让元素探出父容器)
.overlap li { margin-left: -12px; }   /* 头像列表相互叠压的常见写法 */
/* 坑:负 margin 会让内容跑到容器外,窄屏直接溢出出现横向滚动条 */

自查清单

  1. DevTools 选中元素看 Computed 面板的盒子图:绿=content、黄=padding、棕=border、橙=margin。
  2. 「明明设了宽度还溢出」→ 十有八九是 content-box + padding/border。
  3. 「margin 没生效」→ 检查是不是塌陷,或者父是 flex 容器(子的 margin 不塌陷但百分比 margin 行为不同)。
  4. 「最后一个子元素的 margin-bottom 把容器撑高」→ 塌陷穿透到底部,给容器加 padding-bottom 或改用 gap。