从 float 到 Grid:我的页面布局学习笔记
我学布局的顺序和大多数人差不多:早年靠 float,flex 用熟觉得解放了,grid 是到这两年才真正开始写。中间有一阵我以为 flex 能替代一切,结果该用 grid 的地方硬用 flex,代码写得比布局本身还复杂。这篇记下三代布局各自真正该用在哪。版本环境是 2026 年 9 月的 Chrome 130 和 Firefox 132,这三个特性都不需要前缀。
第一代:float,它本来不是拿来做布局的
float 原本只解决一件事:让图片旁边的文字能绕上去。把块级元素并排,是当年顺手拿它干了不该干的活,所以处处别扭。我踩得最狠的是两个坑。
坑一:父容器高度塌陷
子元素全部 float 之后,父容器算出来的高度是 0,背景色一打开就露馅,下面的内容直接涌上来。当年的解法是在末尾加一个看不见的清除元素,后来统一成 clearfix:
.clearfix::after {
content: "";
display: block;
clear: both;
}
这五行我抄过无数遍,却一直没懂它为什么有效。后来查 BFC 才明白:这个 display: block 的伪元素是正常流里的盒子,父容器为了包住它,只能把高度重新撑开。
坑二:BFC 到底是玄学还是有规则
float 时代到处让人「触发 BFC」,最流行的做法是随手加一个 overflow: hidden。我后来把它记成一句人话:BFC 是一块独立的排版区域,里面怎么排不影响外面,外面的浮动也进不来。常用手段有四种:
overflow不为visible,最常见的是hiddendisplay: flow-root,专门为这件事而生,副作用最小float不为none,或者position是absolute、fixed- 弹性容器和网格容器的直接子元素会自动进入类似状态
现在的习惯是:要清除浮动或者阻止相邻外边距折叠,一律用 display: flow-root。我不再拿 overflow: hidden 顶替,它的副作用我吃过:子元素的投影被裁掉一半。
第二代:flex,尺寸由内容说了算的时候用它
flex 的核心心智是一条主轴加弹性分配:容器给一条线,子项按需占空间。合适的场景是导航条、按钮组、标签行这类——每项多宽我不知道,能塞进可用空间就行。
坑:min-width: auto 让子项撑破容器
这是 flex 最经典的一个坑,我第一次遇到时以为是浏览器 bug。flex 子项的 min-width 默认值不是 0 而是 auto,意思是「我不小于自己内容的固有宽度」。于是当子项里塞了一段长 URL,或者一块 <pre> 代码时,它坚决不肯收缩,直接把容器顶宽,页面出现横向滚动条。
解法很简单,只在「该收缩的那一层」显式允许它收缩:
/* 只给被撑破的那一项加,不要全局加 */
.flex-item {
min-width: 0; /* 行方向把容器顶宽时 */
min-height: 0; /* 列方向把容器顶高时 */
}
我这个站就中招过:正文里一段代码太长,整页跟着变宽。给 pre 外面那层加了 min-width: 0 之后,它自己的 overflow-x: auto 才真的开始生效,变成块内横向滚动。
第三代:grid,尺寸由容器先定下来的时候用它
grid 和 flex 的区别我用一句话记:flex 是「内容决定占多大」,grid 是「我先画好格子,内容往里塞」。凡是脑子里已经出现「几列几行、行列要对齐」的,就该换 grid。
一行代码做响应式
.card-list {
display: grid;
gap: 0.9rem;
grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
这一行我是到 2024 年才真看懂的,看懂之后删掉了手上差不多三十行媒体查询。minmax(13rem, 1fr) 说的是每列最窄 13rem,宽得起就把剩余空间等分;auto-fit 负责按容器当前宽度算放得下几列,放四列不到 13rem 就自动退回三列,全程不需要断点。站点的卡片列表就是这一行,我从 320px 拖到 1920px 验证过。
容易混的一点:auto-fit 和 auto-fill 的差别只在「空出来的格子要不要继续占位」。内容少、希望剩下的列铺满就用 auto-fit;希望格子按网格排、留白也保结构就用 auto-fill。
另外两个常用:grid-template-areas 写整页骨架,媒体查询里只改 areas 不改 HTML;place-content: center 一行做居中,不用算负 margin。
用哪种:我自己那张判断表
后来我不再背特性清单,改成按「尺寸到底谁说了算」来选:
| 尺寸由谁决定 | 我用什么 | 典型场景 |
|---|---|---|
| 由内容决定,一排放得下就行 | flex | 导航、按钮组、标签行 |
| 由容器决定,格子先存在 | grid | 卡片列表、整页骨架 |
| 行列两边都要严格对齐 | grid | 日历、表格式排版 |
| 只是文字绕着图走 | float | 正文里的插图,仍然是它 |
| 脱离文档流的浮层 | position | 角标、返回顶部按钮 |
「一维还是二维」对我太抽象,实际用的是另一个问法:把这块内容全删掉,结构还成立吗?成立说明格子先存在,用 grid;不成立、形状完全是内容撑出来的,用 flex。
小结
三代布局不是替代关系:float 我留着给图片环绕,flex 管「一排行不行」,grid 管「整个版面长什么样」。判断顺序也固定了:先问是不是二维,是就上 grid;不是就问尺寸归谁,归内容就 flex,真的只是文字绕图才用 float。
这些都是搭这个站时踩完再回头查的,措辞和规范不一定完全一致,但够让我下次不再问第二遍。