大禹记。

首页 / 文章 / 正文

从 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,最常见的是 hidden
  • display: 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。


这些都是搭这个站时踩完再回头查的,措辞和规范不一定完全一致,但够让我下次不再问第二遍。