编程语言研究书库

CSS 布局 — 定位、flexbox、grid 与长度单位

CSS 布局 — 定位、flexbox、grid 与长度单位

这一章讲一件事:盒子(第 07 章盒模型)摆到哪、怎么排队。 三套机制各管一个层面:四种定位回答「这个盒子相对谁」;flexbox 回答「一排盒子怎么分一条轴」; grid 回答「整个页面怎么切成行和列」;外加老式的 float(认识一下,然后告别)和长度单位(所有尺寸的词汇表)。 学完这章,你就能把第 13 章那个真实应用的全部布局读明白了。

1. 先看现象:为什么「摆几个盒子」需要三套机制

想象你要排一个页面:顶上一条导航、中间左文右图、底部页脚。 「左文右图」用 flexbox 一行就够;但「整个页面五块区域各就各位」就要同时管行和列。 反过来,如果一个按钮组只需要「三个按钮均匀站开」,上 grid 就是杀鸡用牛刀。

这一章的三套机制不是三个世代的前后替代,而是三个不同问题的答案—— 虽然它们确实有年代顺序(定位 → float → flexbox → grid),各自还活着的原因是对应的问题永远存在。 原书给的分工口诀,今天仍然成立:一维用 flexbox,二维用 grid1。

2. 顶层全景:三套机制一张图

  position(管“相对谁”):                flexbox(管“一条轴怎么分”):        grid(管“行×列一起切”):
  static    正常排队(默认)             display: flex 开工               display: grid 开工
  relative  相对自己原来站的位置        flex-direction: row/column       grid-template-columns: 1fr 1fr
  absolute  移出队伍,相对最近的有       flex-wrap: wrap 窄了换行          grid-template-rows: auto…
            定位的祖先                                          grid-column: 1 / 5(占 1 到 5 线)
  fixed     钉在窗口上,滚动不挪          ← 元素可伸缩(grow/shrink)       grid-row: 3 / 4(占第 3 行)

  图说:定位回答“相对谁”,flex 回答“一条轴怎么分”,grid 回答“整张网怎么织”。

3. 定位:四种 position,一个关键问题「移不移出队伍」

position 属性有四种常用值,书里逐个讲的2。理解它们的钥匙只有一个: 这个元素还占不占它原来的位置(文档流)?它相对谁量坐标?

static(静态)——默认,也是基准。 所有元素默认就是 static:按 HTML 书写顺序一个个排队, 此时 top/left 等偏移属性无效3。记住这条,因为后面三种全是「相对 static 那个本该在的位置」说话的。

relative(相对定位)—— visually 挪开,原位还占着。 元素相对自己 static 时本该在的位置偏移: position: relative; top: 20px; = 「从你本来的位置向下挪 20 像素」4。 关键在书里点破的那半句:它原来的位置仍然被占着——别的元素不会挤进来。 所以 relative 最适合「把这个标签轻轻挪一点」这种微调,也最常当一个「锚」:它是 absolute 的参照物(见下)。

absolute(绝对定位)——移出队伍,相对最近的有定位祖先。 元素脱离文档流: 不占空间,其他元素当它不存在5。它的坐标相对谁?答案是「离它最近的那个非 static 祖先」—— 如果一路上都没有,就相对整个页面。所以 absolute 的经典搭档是: 父元素设 position: relative(原地不动但获得「定位上下文」),子元素设 position: absolute; top: 0; right: 0; (钉在父元素的右上角)。对话框的关闭按钮、图片角上的徽章,全是这个组合。

fixed(固定定位)——钉在窗口上。 也脱离文档流,但坐标相对浏览器窗口: 页面滚动它不动6。「回到顶部」按钮、吸顶导航,都是 fixed。 它和 absolute 的差别就是参照物:窗口 vs 祖先。

  队伍:  [A][B][C]  ← B 设 relative、top:20px:A 和 C 不动,B 视觉上往下挪了
        [A]   [C]   ← B 设 absolute:A、C 挤过来,占位消失,B 悬在原位置上方
  窗口:  [A][B]
         滚滚滚…
        [A][B]      ← B 设 fixed:滚动不换位置

  图说:relative 挪人不挪位;absolute/fixed 连位带人一起摘出队伍。

4. flexbox:一维布局的发动机

flexbox 解决的问题:一组盒子沿一条轴(横排或竖列)怎么分配空间—— 哪些撑大、哪些缩小、窄了怎么办。容器上写一句 display: flex,它的直接子元素立刻变成「弹性项」, 空间多了会分,空间少了会缩7。

  .flex-container { display: flex; }   ← 容器:宣布“我里面的孩子是弹性项”
      ┌──┐ ┌──┐ ┌──┐                  ← 弹性项:沿主轴排队
      │1 │ │2 │ │3 │
      └──┘ └──┘ └──┘

  图说:flex 管的是“这一排(或这一列)的伸缩与对齐”,管不了第二维。

三个最常用调节项,书里都教了:

调节项值干什么
flex-directionrow(默认)/ column主轴方向:横排还是竖列8
flex-wrapnowrap(默认)/ wrap装不下时:硬挤还是换行9

flex-wrap: wrap 是 flexbox 变成「半响应式」的开关:书里让你把浏览器窗口拉窄, 三个盒子装不下时自动换到下一行10——没写一行媒体查询,布局自己适应了。 当然这只是 flex 轴向上的自适应;真正全套的响应式是第 09 章。

flexbox 的边界要心里有数: 它只有一条轴。当布局需要「这个占两列、那个占一行」这种二维控制时, 就该 grid 上场。书里把话说得很直:flexbox 适合一维,grid 适合二维11。

判断(我们的,不是书里的): 书教 flexbox 只教到 direction 和 wrap, 没教 justify-content(主轴上怎么分布:居中/两端/均匀)和 align-items(交叉轴上怎么对齐)—— 而这两个才是 flexbox 日常用得最多的调节项,第 13 章的项目里其实偷偷用了 (justify-content: space-between 把任务文字和按钮分居左右)。 读者需要自己顺着「分布/对齐」这个缺口补一刀。这是本书的选择性简化,不算错,但要知道缺口在哪。 如果错,会错在: 如果哪天 CSS 出了真正一统的布局机制,flex/grid 的分工口诀会失效—— 但截至 2026 年,这句口诀仍是这一行面试题的标准答案。

5. grid:二维布局,整页一「网」打尽

grid 解决的问题:同时定义行和列,让元素像棋子一样摆进格子里。 容器写 display: grid,然后用两条属性织网、两条属性摆子12。

织网:

body {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;  /* 四列,等宽 */
    grid-template-rows: auto auto auto auto;   /* 四行,高度随内容 */
}

fr 是 grid 的招牌单位——fractional unit(分数单位):把容器里剩的空间按份分, 1fr 1fr 1fr 1fr 就是四等份13。auto 则是「这行多高随内容定」。注意这和第 07 章「width: 400px」 的思路本质不同:px 是写死的,fr 是按比例分剩下的——窗口变宽每列一起变宽。

摆子:每个子元素用「起止线」报位置,语法是 起 / 止(网格线从 1 开始数):

header { grid-column: 1 / 5;  grid-row: 1 / 2; }  /* 占满 4 列,在第 1 行 */
main   { grid-column: 1 / 4;  grid-row: 3 / 4; }  /* 占前 3 列 */
aside  { grid-column: 4 / 5;  grid-row: 3 / 4; }  /* 占最后 1 列 */
footer { grid-column: 1 / 5;  grid-row: 4 / 5; }  /* 第 4 行,通栏 */
  线1        线2        线3        线4        线5
  ┌────────────────────────────────────────────────┐ 线1
  │                 header (1/5, 1/2)              │
  ├────────────────────────────────────────────────┤ 线2
  │                 nav   (1/5, 2/3)               │
  ├───────────────────────────────┬────────────────┤ 线3
  │      main (1/4)               │ aside (4/5)    │
  ├───────────────────────────────┴────────────────┤ 线4
  │                 footer (1/5, 4/5)              │
  └────────────────────────────────────────────────┘ 线5

  图说:列线竖着数 1–5,行线横着数 1–5;“1 / 5” = 从 1 号线到 5 号线,恰好通栏。

这就是第 09 章响应式改造的底子:到时候不需要重写这个结构,只要在媒体查询里重排这些起止线, 同一批元素就能在手机上单列堆叠。grid 结构 + 媒体查询重排,是 2026 年响应式的主流打法之一。

6. float 与 clear:遗产课

在 flexbox/grid 之前(大约 2005–2015),网页布局靠的是一对原始工具: float 最初的设计用途是让文字绕图排版(图片浮在左/右,文字围过去)14; 后来被强行征用做整页布局——那段历史催生过无数「清除浮动」的邪派武功。 clear 是配套的刹车:阻止元素绕到浮动元素旁边,把它强制压到浮动元素下方15。

书里给的结论可以直接当这一行的公论:float 和 clear 如今很少用于布局, flexbox 和 grid 更好,尽量别用 float 做布局16。它剩下的正当用途只有一个:文章里的图文混排。 读老代码时会大量遇到 float: left + 各种 clearfix——认识它,是为了看懂过去,不是为了用它。

7. 长度单位:尺寸的词汇表

所有 width、height、padding、margin 都要带单位。书里把单位分成绝对、相对两家17:

类别单位含义典型场景
绝对px像素,屏幕上的点边框、小图标
绝对pt磅,印刷单位(1pt ≈ 1.33px)字号的历史习惯
绝对in / mm英寸 / 毫米打印样式表
相对%父元素对应尺寸的几成宽度、高度的一半份额
相对em当前元素字号的几倍间距随字号走
相对fr剩余空间的几份(grid/flex 语境)网格列宽

em 值得单独看一眼,书里给了算式:字号 12pt 时,2em = 24pt,1.5em = 18pt18—— em 的参照物是「当前字号」,所以用 em 写的间距会跟着字号缩放,这就是它适合做「内边距跟着文字走」的原因。 (它的亲戚 rem——相对根元素字号——本书没提,日后见到知道是「永远相对页面默认字号」的 em 就行,④ 类补充。)

为什么单位分两家的根本理由是响应式(第 09 章的入场券): 绝对单位不知道屏幕变了, 相对单位知道。「用 % 和 fr 写骨架,用 px 写细节」是这一行的默认值。

8. 主线例子:一个页面骨架的三种摆法

这一章的主线例子,是书里那个四列四行的餐厅页面骨架(header/nav/main/aside/footer), 同一个目标用三套机制各摆一遍(尺寸数字沿用书中例子,便于对照):

  目标:header 通栏、nav 通栏、main 占 3 列、aside 占 1 列、footer 通栏

  摆法一(position 时代——书里没这么教,2010 年代实况):
      aside { float: right; width: 25%; }
      main  { margin-right: 25%; }        ← 手动给 aside 让位;浮动溢出还要 clear 收拾

  摆法二(flexbox——只能一维,要嵌套):
      body { display: flex; flex-direction: column; }   ← 先竖排五大块
      中间再包一层 div { display: flex; }              ← 再横排 main 和 aside
      ← 为了布局多造了一层无意义标签,是 flexbox 时代的典型代价

  摆法三(grid——书里教的做法,二维一次到位):
      body { display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; }
      header { grid-column: 1 / 5; } main { grid-column: 1 / 4; }
      aside { grid-column: 4 / 5; } footer { grid-column: 1 / 5; }
      ← 结构标签一个没多加,行列各归各位

  图说:同一个骨架,float 要靠“让位”骗、flex 要靠嵌套凑、grid 直接说——这就是三代工具的差距。

这个对照是本章的落点: 不是「grid 最新所以最好」,而是表达力的差别—— grid 让你用结构本身的语言(行、列、占几格)描述布局,而不是借别的机制打比方。 这也是为什么今天的新项目默认 grid/flex,float 只剩博物馆。

9. 作者的判断与证据

书内作为事实给出的: 四种 position 的语义(尤其 relative 占原位的细节、absolute 脱流)45、 flex 与 grid 的一维/二维分工11、fr 的含义13、float 的原始用途与退场1416、单位两家分类17。

需要以标准为准修正原书的地方: 书里多处写 flex-direction: rows/columns(复数), CSS 规范的值是单数 row/column8;引用时以单数为准,书中显然是笔误。 另外 grid 例子的 HTML 用了 <header>、<nav>、<main>、<aside>、<footer> 这组语义化标签—— 书里直接用但没解释,我们补上:这组标签是「页面区域的身份声明」,和 <strong> 一个道理, 对搜索引擎和读屏软件说「这是导航、这是正文」。第 13 章会再用一次。

10. 边界与局限

  • flexbox 教得浅: justify-content/align-items/gap 这三个日常调节项没教(第 13 章的项目代码里却出现了)——缺口要自补。
  • grid 没教 grid-template-areas:那是比「起止线」更好读的网格摆法(给每个区域起名字再摆名字),入门之外的第一课。
  • 定位没教 z-index 与层叠上下文:多个 absolute/fixed 元素重叠时谁压谁,是个有独立深度的话题,本书完全没碰。
  • rem、vw/vh 没提;min-width/max-width 要到第 09、13 章才实际出现。

11. 可带走的

全章主线例子,一行写完: 同一个五区骨架,float 靠让位、flex 靠嵌套、grid 靠 grid-column: 起/止 一句话——表达力就是三代的差距。

  1. position 的钥匙是「移不移出队伍、相对谁量坐标」:static 默认、relative 挪位不占队、absolute 出队相对非 static 祖先、fixed 钉窗口2;
  2. absolute 的经典搭档:父 relative + 子 absolute(关闭按钮、角标);
  3. flexbox = 一条轴的分配;两个开关:flex-direction(横/竖)、flex-wrap(换行)89;
  4. grid = 行列一起织:display: grid + grid-template-columns/rows 织网 + grid-column/row: 起/止 摆子;
  5. fr 按份分剩余空间,auto 随内容——相对单位是响应式的入场券;
  6. float 只做图文混排,布局别碰;clear 是配套的刹车16;
  7. 单位两家:绝对(px/pt)写细节,相对(%/em/fr)写骨架;
  8. 一维 flex、二维 grid——这句口诀 2026 年仍是标准答案11。

12. 原文地图

主题原书章原文位置
static 默认与偏移无效CSS for Layoutstext/14-fm-introduction.txt:31(搜「default positioning of all elements」)
relative 相对原位、原位仍占CSS for Layoutstext/14-fm-introduction.txt:35(搜「positioned relatively」)
absolute 脱离文档流CSS for Layoutstext/14-fm-introduction.txt:43(搜「positioned as absolute」)
fixed 相对浏览器窗口CSS for Layoutstext/14-fm-introduction.txt:47(搜「fixed positioning is removed」)
flex 容器与方向CSS for Layoutstext/14-fm-introduction.txt:61(搜「display: flex」) · text/14-fm-introduction.txt:75(搜「flex-direction」)
flex 换行CSS for Layoutstext/14-fm-introduction.txt:107(搜「flex-wrap」) · text/14-fm-introduction.txt:119(搜「make it smaller」)
grid 织网与 frCSS for Layoutstext/14-fm-introduction.txt:145(搜「fractional unit」) · text/14-fm-introduction.txt:153(搜「grid-template-columns: 1fr」)
grid 摆子(grid-column/row)CSS for Layoutstext/14-fm-introduction.txt:163(搜「grid-column: 1 / 5」)
float 的本来用途CSS for Layoutstext/14-fm-introduction.txt:325(搜「float property was originally」)
clear 的作用CSS for Layoutstext/14-fm-introduction.txt:337(搜「clear property prevents」)
float 退场建议CSS for Layoutstext/14-fm-introduction.txt:339(搜「much better to use flexbox or grid」)
单位两家分类CSS for Layoutstext/14-fm-introduction.txt:345(搜「same size regardless」) · text/14-fm-introduction.txt:385(搜「fractional unit」)
章末:一维/二维分工CSS for Layoutstext/14-fm-introduction.txt:415(搜「flexbox is best suited」)

Footnotes

  1. 出处:「CSS for Layouts」第 415 段(text/14-fm-introduction.txt:415,搜「flexbox is best suited」)。原文:「Flexbox is best suited for one-dimensional layouts, while CSS grid is more effective for two-dimensional layouts involving both rows and columns.」 ↩

  2. 出处:「CSS for Layouts」第 29 段(text/14-fm-introduction.txt:29,搜「four commonly used values」)。原文列出 position 的四个常用值:static、relative、absolute、fixed。 ↩ ↩2

  3. 出处:「CSS for Layouts」第 31 段(text/14-fm-introduction.txt:31,搜「default positioning of all elements」)。原文:「Static-positioned elements are not affected by the top, bottom, left, and right properties.」 ↩

  4. 出处:「CSS for Layouts」第 35 段(text/14-fm-introduction.txt:35,搜「positioned relatively」)。原文:「Setting the top, right, bottom, and left properties will move the element visually away from its original position.」 ↩ ↩2

  5. 出处:「CSS for Layouts」第 43 段(text/14-fm-introduction.txt:43,搜「positioned as absolute」)。原文:「it is removed from the normal document flow... other elements will ignore its presence.」 ↩ ↩2

  6. 出处:「CSS for Layouts」第 47 段(text/14-fm-introduction.txt:47,搜「fixed positioning is removed」)。原文:「positioned relative to the browser window. It stays fixed in its position even when the page is scrolled.」 ↩

  7. 出处:「CSS for Layouts」第 53–65 段(text/14-fm-introduction.txt:53,搜「layout model」;:61,搜「display: flex」)。原文:「The flex property in the display element specifies how a flex item will grow or shrink to fit the space available in its container.」 ↩

  8. 出处:「CSS for Layouts」第 75–95 段(text/14-fm-introduction.txt:75,搜「flex-direction」)。原文意图为 row/column;书中写作 rows/columns 是笔误,以 CSS 标准(单数)为准。 ↩ ↩2 ↩3

  9. 出处:「CSS for Layouts」第 99–109 段(text/14-fm-introduction.txt:107,搜「flex-wrap」)。原文:「the items will wrap to the next row if the screen size is smaller.」 ↩ ↩2

  10. 出处:「CSS for Layouts」第 119 段(text/14-fm-introduction.txt:119,搜「make it smaller」)。原文:「Now, when we resize the browser window, for example, make it smaller, you can see the flexbox items wrap.」 ↩

  11. 出处:「CSS for Layouts」第 415 段(text/14-fm-introduction.txt:415,搜「flexbox is best suited」)。 ↩ ↩2 ↩3

  12. 出处:「CSS for Layouts」第 125–153 段(text/14-fm-introduction.txt:125,搜「layout system」;:143,搜「grid container with four columns」;:153,搜「grid-template-rows: auto auto auto auto」)。 ↩

  13. 出处:「CSS for Layouts」第 145 段(text/14-fm-introduction.txt:145,搜「fractional unit」)。原文:「The unit fr stands for fractional unit and is used to allocate a proportion of the available space within the grid container.」 ↩ ↩2

  14. 出处:「CSS for Layouts」第 325 段(text/14-fm-introduction.txt:325,搜「float property was originally」)。原文:「The float property was originally used to wrap text around images, although it is used less frequently today thanks to flexbox and grid.」 ↩ ↩2

  15. 出处:「CSS for Layouts」第 337 段(text/14-fm-introduction.txt:337,搜「clear property prevents」)。 ↩

  16. 出处:「CSS for Layouts」第 339 段(text/14-fm-introduction.txt:339,搜「much better to use flexbox or grid」)。原文:「It is much better to use flexbox or grid.」 ↩ ↩2 ↩3

  17. 出处:「CSS for Layouts」第 341–385 段(text/14-fm-introduction.txt:345,搜「same size regardless」)。原文:「Units that are absolute are the same size regardless of the parent element or window size.」 ↩ ↩2

  18. 出处:「CSS for Layouts」第 377 段(text/14-fm-introduction.txt:377,搜「12 x 2」)。原文:「If a font is set to 12pt, each em unit would be 12pt, so 2em would be 12 x 2, which is 24pt.」 ↩

On this page