前置知识: HTML5、CSS

盒模型、间距与尺寸

10 min入门

Tailwind CSS 布局地基:文档流与 display、盒模型与 border-box、尺寸类(w/h/max/min)、margin 家族与负值、space-* 兄弟间距,配盒模型实证与阅读宽度等示例

知识点地图

  • 知识类别:CSS 布局地基——文档流、display、盒模型(box-sizing),以及 Tailwind 的尺寸类与 margin 间距体系。
  • 解决什么问题:理解元素”默认怎么排、默认多大、间距从哪来”,进而精确控制盒子的宽度高度、内外留白与水平居中——这是一切布局的最底层。
  • 什么时候用到:写任何布局之前。一维的 Flex 与二维的 Grid 都建立在这套地基上:盒子的尺寸与间距没想清楚,再高阶的布局也会塌。
  • 一维排布(Flex)在Flexbox 一维弹性布局展开,二维版面与悬浮层在Grid 网格布局与定位与层叠上下文展开。

前置知识

学习目标

  • 理解文档流、display 与盒模型如何决定元素的默认排布与默认尺寸。
  • 说清 Tailwind 预设的 border-box 意味着什么,w-24 到底量到哪里,第三方样式覆盖时怎么排查。
  • 能用 w-*/h-*/max-w-*/min-h-* 控制盒子尺寸,理解 min-w-0 与 max-w-* 这两个”反直觉救命类”的用途。
  • 能用 margin 家族(含负值与 mx-auto)与 space-y-* 管理间距,知道它们与 gap-* 的分工边界。

0. 摆积木的排布学问

儿童玩具桌上有两盒积木。第一盒是”串珠”:一根绳子,把珠子一颗颗穿进去,顺序固定、方向单一,只能排成一列或一串——这是一维排布。第二盒是”底板”:一块带凸点的塑料板,积木可以横着放、竖着放、跨两格、占满一行——这是二维排布。

网页布局和摆积木是同一件事:决定”谁在谁旁边、谁占多大地方、空间多了怎么办”。CSS 为此提供了两套排布系统:**Flex(弹性盒子)**像串珠,擅长一维排布(一行或一列),详见Flexbox 一维弹性布局;**Grid(网格)**像底板,擅长二维排布(行列同时控制),详见Grid 网格布局。

但无论用哪套系统排,每颗珠子、每块积木自己先得是个有确定大小、有确定内外留白的盒子——这盒子的学问(文档流、display、盒模型、尺寸与间距)就是本篇的内容。它是 Flex 与 Grid 之前的必修课。

1. 布局的起点:文档流与盒模型

在认识 Flex 与 Grid 之前,先理解它们出现之前的世界——普通文档流(normal flow)。

1.1 块级与行内

HTML 元素天然分两类:

  • 块级元素(div、p、h1、section):独占一行,宽度默认占满父容器,从上到下堆叠。
  • 行内元素(span、a、strong):随文本从左到右排列,一行放不下才换行,宽度由内容决定。
html
<!-- 三个块级元素:上下堆叠 -->
<div class="bg-blue-100 p-2">块一:独占一行</div>
<div class="bg-blue-100 p-2">块二:独占一行</div>

<!-- 三个行内元素:从左到右流动 -->
<span class="bg-green-100 px-2">行内一</span>
<span class="bg-green-100 px-2">行内二</span>
<span class="bg-green-100 px-2">行内三</span>

普通文档流的问题是:无法精确控制排布方向与对齐方式。想让两个块并排、让元素垂直居中、让某块占剩余空间——靠文档流都做不到。于是 CSS 引入了”主动布局”方案:一维的 Flex 与二维的 Grid(分别见姊妹篇)。

1.2 一切布局的前提:display

display 属性决定元素以何种身份参与布局。Tailwind 提供了对应的工具类:

类名CSS 值用途
blockdisplay: block强制块级
inlinedisplay: inline强制行内
inline-blockdisplay: inline-block行内但可设宽高
flexdisplay: flex开启弹性布局(详见Flexbox 一维弹性布局)
griddisplay: grid开启网格布局(详见Grid 网格布局)
hiddendisplay: none从页面移除元素
html
<!-- span 变成块级:独占一行 -->
<span class="block bg-gray-100 p-2">我是 span,但显示为块级</span>

<!-- div 变成行内块:可设宽度,又随文本排列 -->
<div class="inline-block w-24 bg-gray-100 p-2">行内块</div>

<!-- 响应式显隐:移动端隐藏,桌面端显示 -->
<div class="hidden md:block bg-gray-100 p-2">桌面端才显示</div>

讲解:hidden 配合断点前缀(md:block)是”移动端隐藏/桌面端显示”的常用手段,无需手写媒体查询。还有一个隐蔽规则:行内元素设置宽高无效——<span class="w-24"> 不生效,必须先改成 inline-block 或 block。排查”宽高类写了没反应”时,第一反应就查元素的 display。

1.3 盒模型与 box-sizing:Tailwind 已替你选好

每个元素都是一个”盒子”,由四层组成:内容(content)→ 内边距(padding)→ 边框(border)→ 外边距(margin)。w-*、h-* 量的是哪一层,由 box-sizing 决定:

box-sizingw-24(96px)量到哪里手工算尺寸时
content-box(CSS 默认)只量内容区;加 p-4 后实际占 96 + 32 = 128px要自己做减法,容易错
border-box(Tailwind 预设)内容 + 内边距 + 边框合计 96px写多少就是多少

Tailwind 的 Preflight(预检样式)把所有元素的 box-sizing 统一设为 border-box,所以”卡片 w-64 p-6 border 仍然正好 256px 宽”。易错点只在一处:当你自己写原生 CSS 或给第三方组件库写覆盖样式时,若忘了对方是 content-box,加 padding 就会把容器撑爆。确认方式:DevTools 选中元素,Computed 面板搜 box-sizing。

html
<!-- border-box 下:总宽就是 w-64 的 256px,padding 向内收缩内容 -->
<div class="w-64 border-4 border-gray-900 bg-blue-100 p-6">总宽恒定 256px</div>

讲解:如果把它改回 content-box([box-sizing:content-box]),同一组类会占到 256 + 48 + 8 = 312px——“写死宽度却仍被撑爆”的悬案多半出在这里。

2. 尺寸类:定宽定高与弹性上下限

尺寸类分四组:固定尺寸、最小尺寸、最大尺寸、按比例。

类名CSS用途
w-64 / h-16width/height: 16rem/4rem固定尺寸,走间距刻度
w-full / h-screenwidth: 100% / height: 100vh撑满父容器 / 满屏高
size-12width + height 同时 3rem正方形速记(头像、图标位)
max-w-md / max-w-2xl / max-w-7xlmax-width: 28rem / 42rem / 80rem内容最大宽度上限
max-w-fullmax-width: 100%不超过父容器(图片防溢出标配)
min-h-screen / min-h-0 / min-w-0min-height/min-width最小尺寸;min-w-0 是防溢出兜底
html
<!-- 头像:size-12 一条顶 w-12 h-12 两条 -->
<img src="/avatar.png" alt="头像" class="size-12 rounded-full object-cover" />

<!-- 阅读宽度:长文限在 42rem 内,一行 60 到 75 个英文字符最舒适 -->
<article class="mx-auto max-w-2xl px-6">
  <p>超过 45rem 的行宽,读者眼睛从行尾扫回行首容易串行——这就是杂志与文档站都给正文限宽的原因。</p>
</article>

<!-- 图片防溢出:容器再窄也不撑破 -->
<img src="/chart.png" alt="图表" class="max-w-full h-auto rounded-lg" />

讲解:max-w-* 的刻度(sm 24rem、md 28rem、lg 32rem、xl 36rem、2xl 42rem、…、7xl 80rem)专为”内容容器”设计。两个高频组合值得背下来:长文正文用 mx-auto max-w-2xl(限宽 + 居中),图片用 max-w-full(在小容器里缩、在宽容器里不放大失真)。min-w-0 看起来无用,实际是 Flex/Grid 布局里”内容里有长 URL/长单词把弹性栏撑爆”的标准解药——默认 min-width: auto 会让子内容拒绝收缩,min-w-0 解除这个下限。深挖见 041 篇动手实践。

3. 间距:margin 家族与兄弟间距

padding 往内撑开盒子,margin 往外推开邻居——间距刻度两者共用(0.25rem 步进,见 030 篇第 3 节)。margin 有三件 padding 没有的本事:负值、auto、与兄弟选择器。

3.1 方向类、负 margin 与 auto

类名CSS用途
mt-8 / mb-4 / ml-2 / mr-2margin-top/bottom/left/right单方向外边距
-mt-2margin-top: -0.5rem负 margin:让元素”越界”
mx-automargin-inline: auto水平居中(块级元素标配)
my-6margin-block: 1.5rem上下同时
html
<!-- 卡片内的节奏:标题与正文拉开 12px,区块之间 24px -->
<div class="rounded-xl border border-gray-200 p-6">
  <h2 class="text-lg font-bold">第 3 章:函数</h2>
  <p class="mt-3 text-sm text-gray-600">函数是一段可复用的代码……</p>
  <div class="mt-6 flex gap-2">
    <span class="rounded bg-gray-100 px-2 py-1 text-xs">示例</span>
    <span class="rounded bg-gray-100 px-2 py-1 text-xs">练习</span>
  </div>
</div>

<!-- 负 margin:图片顶出卡片边界,做出"破格"海报感 -->
<div class="rounded-xl border border-gray-200 bg-white p-4">
  <img src="/cover.png" alt="封面" class="-mt-10 h-28 w-28 rounded-lg border-4 border-white shadow-lg" />
  <h3 class="mt-3 font-semibold">破格封面</h3>
</div>

<!-- 块级水平居中:定宽或限宽 + mx-auto -->
<main class="mx-auto max-w-7xl px-6">
  <p>内容在 1280px 以内水平居中,两侧保留 24px 内边距</p>
</main>

讲解:mx-auto 生效有个前提——元素得有”多余的空间可分”:定宽(w-*)或限宽(max-w-*)之一必须存在,w-full 的元素加 mx-auto 毫无效果。负 margin 的典型用途是”破格”装饰与紧凑叠放;它是唯一能让元素越过父容器内边距的常规手段,但方向要成对想清楚(-mt-10 上移,会不会盖住上一个元素)。

3.2 兄弟间距:space-y-*

给容器里相邻子元素之间统一加间距,一条类替代逐个加 mt-*:

html
<!-- 列表条目统一 16px 垂直间距,不用每个条目写 mt-4 -->
<ul class="space-y-4">
  <li class="rounded bg-gray-100 p-3">条目一</li>
  <li class="rounded bg-gray-100 p-3">条目二</li>
  <li class="rounded bg-gray-100 p-3">条目三</li>
</ul>

讲解:space-y-4 通过相邻兄弟选择器(> * + *)实现,只影响相邻子元素之间,不给首尾元素加外边距。口诀:兄弟之间用 space-* 或 gap-*,自己与外部用 margin——gap 需要 flex/grid 容器(详见 041 篇第 3 节),space-* 在任何容器都能用,但它假设子元素”垂直单列堆叠”,子元素换行成多列时 space-x-* 会只加在每列第一个元素左边(flex 布局下请优先 gap)。

3.3 文字居中与块级居中

需求工具类说明
文字(行内内容)居中text-center文本水平居中
块级元素水平居中mx-auto + 定宽/限宽左右外边距自动平分
html
<!-- 文字居中 -->
<h1 class="text-center text-2xl font-bold">居中标题</h1>

<!-- 限宽居中的页面容器 -->
<div class="mx-auto max-w-3xl px-4">表单、文章等窄内容区</div>

双轴(垂直 + 水平)居中需要 Flex 容器配合,见Flexbox 一维弹性布局第 3 节。

4. 常见错误与对策

错误场景表现原因解决办法
宽度失效子元素设了 w-24 仍占满行内元素宽高无效,或块级宽度受父容器约束先设 inline-block/block;需要并排交给 Flex
写死宽度被撑爆w-64 p-6 border 实际比 256px 宽该元素处在 content-box 上下文(如第三方样式覆盖了 Preflight)检查 box-sizing,补 [box-sizing:border-box] 或全局恢复
mx-auto 不居中mx-auto 加了却没居中元素 w-full 或没设宽度,没有可平分的空隙配 max-w-* 或 w-* 一起用
负 margin 盖住邻元素图片装饰盖住了上一段文字负 margin 让元素越界但层叠顺序没管配合 relative 与 z-* 控制层叠(见 044 篇)
space-x 多列错乱换行布局下第一列左侧多出一条缝space-* 假设子元素单列/单行排列flex/grid 容器统一用 gap-*
内容撑爆弹性栏长 URL 把栏宽顶爆min-width: auto 默认拒绝收缩内容所在栏加 min-w-0

5. 动手实践

任务一:盒模型实证。 写两个 w-40 p-4 border-2 的盒子,一个默认、一个加 [box-sizing:content-box],量出两者实际宽度差并解释。提示:内容 160px;padding 左右各 16px;border 左右各 2px。

任务二:阅读宽度改造。 把一段通栏长文(w-full)改造成”居中限宽”的舒适排版,再解释为什么”只用 max-w 不加 mx-auto”达不到效果。提示:限宽后元素靠左,需要 margin 自动平分来居中。

任务三:破格头像卡。 实现一张”头像一半露在卡片外”的会员卡:卡片有顶部留白,头像用负 margin 上移越界,且头像要盖住卡片边框而不是被边框盖住。提示:-mt-* 负 margin + 父容器不加 overflow-hidden;层叠问题交给 relative。

先自己写,再对照参考实现:

任务一参考实现
html
<div class="w-40 border-2 border-gray-900 bg-blue-100 p-4">border-box:总宽 160px</div>
<div class="w-40 border-2 border-gray-900 bg-blue-100 p-4 [box-sizing:content-box]">
  content-box:总宽 196px
</div>

196px = 内容 160 + 内边距 16 x 2 + 边框 2 x 2。DevTools 的 Computed 面板里两个盒子的 box-sizing 一目了然;把尺寸换算成”内容区 + 四层”的心算习惯,比背口诀更能防坑。真实工程里这个问题最常出现在”往第三方组件里塞 Tailwind 类”的时候——组件库自带的 CSS 可能改回了 content-box。

任务二参考实现
html
<!-- 改造前:通栏正文,行宽随视口无限拉长 -->
<p class="text-gray-700">(长文……)</p>

<!-- 改造后:限宽 + 居中 -->
<article class="mx-auto max-w-2xl px-6 text-gray-700">
  <p>(长文……)</p>
</article>

只写 max-w-2xl 不写 mx-auto 时,块级元素在剩余空间里默认靠左——限宽只回答”最宽多宽”,居中要靠 margin 自动平分回答”空隙怎么分”。px-6 是给窄屏兜底的内边距:视口小于 42rem 时 max-w 不再起作用,两侧留白全靠 padding。这两条合起来就是”长文容器三件套”:mx-auto max-w-2xl px-6。

任务三参考实现
html
<div class="mx-auto max-w-xs rounded-xl border border-gray-200 bg-white px-4 pb-5 pt-12 text-center shadow-sm">
  <img
    src="/avatar.png"
    alt="会员头像"
    class="relative mx-auto -mt-16 size-20 rounded-full border-4 border-white object-cover shadow-md"
  />
  <h3 class="mt-3 font-bold text-gray-900">暮色会员</h3>
  <p class="mt-1 text-sm text-gray-500">头像一半在卡外,一半在卡内</p>
</div>

三个关键点:pt-12 给卡片顶部留出”给头像越过来的空位”;-mt-16 让头像上移出界(头像自身 size-20,一半即 40px,约等于 mt-10,这里取 mt-16 制造更明显的破格);relative 让头像建立定位上下文并抬高绘制层级,配合白色粗边框盖住卡片边框线。若把 -mt-16 写成 mb-* 方向,头像只会把内容往下推——负 margin 是”位移”语义,正 margin 是”占位”语义,这组对照值得亲手各写一遍体会差别。

6. 一句话记忆

每颗珠子自己先是个盒子:文档流决定默认排法,display 决定参与身份,border-box 让”写多少是多少”;尺寸用 w/h/size/max-w/min-w-0,间距靠 margin 三件套(方向类、负值、mx-auto)与兄弟选择器 space-*,一维排布与 gap 交棒给Flexbox 一维弹性布局。

7. 相关阅读