CSS 入门到入坑的分水岭就在布局:散着写几个属性谁都会,但「这个元素为什么跑这儿了」一旦发生,不懂布局模型的人只能瞎改。本章按「定位 → 浮动(历史课)→ flex → grid → 响应式」推进,我的学习路径建议是:前两节理解原理即可,80% 的日常布局交给 flex 和 grid,它们是为了「不用理解文档流玄学」而生的。
position 决定元素以什么为参照物摆放:
| 值 | 参照 | 脱离文档流 | 典型用途 |
|---|---|---|---|
| static | 默认文档流 | 否 | 不写定位就是它 |
| relative | 自己原来的位置 | 否(占位保留) | 微调、给 absolute 当锚 |
| absolute | 最近的已定位祖先 | 是 | 角标、弹层 |
| fixed | 浏览器视口 | 是 | 悬浮按钮、吸底导航 |
| sticky | 滚动容器 | 否(占位保留) | 吸顶表头 |
最常用的组合是「父 relative + 子 absolute」:父元素设 relative(哪怕 offset 全 0)成为锚点,子元素的 top/right 才有正确的参照:
.card { position: relative; }
.card .badge { position: absolute; top: -8px; right: -8px; } /* 右上角冒出去 */
absolute 脱离文档流后原位置塌掉,后续元素会补上来,重叠就发生在这。fixed 相对视口,滚动时纹丝不动(注意:祖先有 transform 时 fixed 会改相对那个祖先,灵异问题之一)。sticky 是现代宝藏:position: sticky; top: 0 的表头滚过就吸顶,一行 CSS 替代过去几十行 JS 监听滚动。
float 的出身是「文字环绕图片」(杂志排版),被上一代开发者硬当布局用,然后踩了几十年「父容器高度塌陷」的坑:子元素全部浮动后脱离文档流,父容器高度归零,后面的内容窜上来。
.clearfix::after { content: ""; display: block; clear: both; } /* 经典清浮动补丁 */
今天还需要它吗?文字环绕(真正本职)用它;布局别用,flex 完胜。认识 float 和 clearfix 的价值在于:接手老项目和看懂「前辈为什么要转行用 flex」。
把容器变成 flex 后,子项沿一条主轴排列,几乎覆盖所有「一排/一列」的需求:
.container {
display: flex;
flex-direction: row; /* 主轴:row | column */
justify-content: space-between; /* 主轴对齐(两端分散) */
align-items: center; /* 交叉轴对齐(垂直居中) */
gap: 16px; /* 子项间距,比 margin 干净 */
}
.item { flex: 1; } /* 均分剩余空间 */
三件套记忆法:justify-content 管主轴方向的对齐,align-items 管交叉轴的垂直对齐,flex 子项属性管怎么分地盘。flex: 1 是 flex-grow:1; flex-shrink:1; flex-basis:0% 的简写:地盘按份均分,空间不够按比例收缩。那道「CSS 怎么垂直居中」的世纪难题,flex 时代的答案就两行:
.center { display: flex; justify-content: center; align-items: center; }
导航条、卡片横排、侧边栏 + 内容的「左固定右自适应」(.sidebar { flex: 0 0 200px } .main { flex: 1 }),全是 flex 的舒适区。
grid 同时管行和列,先画格子再放东西:
.page {
display: grid;
grid-template-columns: 240px 1fr; /* 侧栏 + 主区 */
grid-template-rows: auto 1fr auto; /* 头 / 主体撑满 / 脚 */
min-height: 100vh;
}
.page > header { grid-column: 1 / -1; } /* 头部横跨两列(-1 = 最后一条线) */
.page > footer { grid-column: 1 / -1; }
fr 是「份」(1fr 和 2fr 按 1:2 分剩余空间),配合 minmax(200px, 1fr) 可以表达「最少 200,多余随便」。响应式网格的神级一行:grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)),容器塞得下几列就几列,卡片墙零媒体查询自适应。选型口径:整页骨架、需要行列对齐,grid;一排东西的排布,flex;两者嵌套组合(外 grid 搭骨架,内 flex 排细节)是常态,不是二选一。
/* 移动优先:基础样式按手机写,向上增强 */
.cards { flex-direction: column; }
@media (min-width: 768px) { /* 平板起,变成横排 */
.cards { flex-direction: row; }
}
min-width 写法(移动优先)是现代惯例:从小屏往上叠加,窄屏的简单规则是地基。断点数字(576/768/992/1200)是参考,真正的原则是内容什么时候挤了,断点就设在哪。媒体查询生效的前提是第 1 章那个 viewport meta(漏了它手机按桌面宽渲染,一切媒体查询白写)。DevTools 的设备模拟器(Ctrl+Shift+M)是响应式开发的显微镜,写完必过一遍。
min-width: 0(flex 子项默认不能小于内容宽度,这个默认值反直觉)。align-items: stretch(默认)被你覆盖了;等高的坑常在 align 系属性。repeat(auto-fill, minmax(240px, 1fr)) 做自适应卡片墙,拖动 DevTools 窗口宽度看列数自动增减,零媒体查询。