知

模块三 · 样式与类型

第 9 / 14 节19 分钟阅读型

CSS 布局与层叠:把页面摆对

布局问题大多不是"属性没记住",而是盒模型、包含块、BFC 与层叠上下文没理清。这一节按这四条主线把 CSS 讲成可推理的规则。

读完这一节,你能做到

  1. 用盒模型与包含块解释一个元素的最终尺寸与位置。
  2. 说清 BFC 解决什么问题、怎么触发。
  3. 判断 z-index 为什么"不生效"。
  4. 在 Flex 与 Grid 之间做出有依据的选择。

一、盒模型与包含块

每个元素都是一个盒子:content + padding + border + margin。

box-sizing: content-box; /* 默认:width 只算 content */
box-sizing: border-box; /* width 包含 padding 与 border */

工程上通常全局设 border-box,让"宽度"符合直觉。

包含块决定百分比宽度、绝对定位的参照:

position包含块
static/relative最近的块级祖先的内容盒
absolute最近的定位祖先的 padding 盒
fixed视口
sticky最近的滚动容器

很多"绝对定位跑偏"的问题,都是因为没找到真正的包含块。

二、BFC:块级格式化上下文

BFC 是一个独立的渲染区域,内部的布局不影响外部。它能解决:

  • 浮动元素导致父容器高度塌陷。
  • 相邻元素 margin 折叠。
  • 浮动元素环绕文字。

触发方式(任选其一):overflow 非 visible、display: flow-root、position: absolute/fixed、float 非 none、contain: layout。

推荐 display: flow-root:语义清晰、没有副作用,不像 overflow: hidden 会裁剪内容。

三、层叠上下文与 z-index

z-index 只在同一层叠上下文内比较。以下情况会创建新的层叠上下文:

  • 根元素。
  • position 非 static 且 z-index 非 auto。
  • opacity < 1、transform、filter、will-change。
  • isolation: isolate。

所以一个父元素设了 transform,子元素的 z-index: 9999 也可能压不过外部的元素——它只在父级上下文内有效。

调试方法:从目标元素往上找,看哪一层创建了新的上下文。

四、Flex 与 Grid 怎么选

维度FlexGrid
方向一维(行或列)二维(行与列)
适合导航、工具栏、卡片内部页面骨架、卡片网格
对齐主轴 + 交叉轴行轴 + 列轴
自适应flex: 1 分配剩余空间minmax + auto-fit

一个实用判断:只需要在一个方向上分配空间,用 Flex;需要同时控制行和列,用 Grid。

五、响应式:三种手段

  1. 媒体查询:按视口宽度切换布局,适合页面级断点。
  2. 容器查询:按父容器宽度切换,适合组件级自适应。
  3. 流式单位:clamp()、min()、max()、fr,让尺寸连续变化。
.card {
  width: clamp(240px, 30vw, 360px);
}
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

优先用流式布局,减少断点数量;断点只处理"结构变化",不要为每个尺寸写一套。

六、常见布局问题

  • 水平垂直居中:Flex 的 justify-content + align-items 最稳;绝对定位 + transform 适合脱离文档流。
  • 两栏等高:Flex 默认 stretch;Grid 也天然等高。
  • 圣杯布局:Grid 的 grid-template-areas 最直观。
  • 文字溢出:单行 text-overflow: ellipsis + white-space: nowrap;多行用 -webkit-line-clamp。
  • 1px 边框:高倍屏用 transform: scaleY(0.5) 或直接接受。

七、常见坑

  1. 给所有元素设 border-box 后,仍按 content 宽度算。
  2. 用 overflow: hidden 清浮动,裁掉了下拉菜单。
  3. z-index 不生效,实际是父级创建了新层叠上下文。
  4. Flex 子项不换行,忘了 flex-wrap。
  5. Grid 的 1fr 被内容撑破,需要 minmax(0, 1fr)。

八、动手任务:自写 → AI 写 → 对比 → 取舍

四步不跳:① 自己写(限时,关掉补全)→ ② 让 AI 写同一题 → ③ 逐条比对 → ④ 说出保留谁的写法。 完整动作与记录模板见《AI 协作与代码评审》。

① 自己写

  1. 用 flow-root 修一次高度塌陷,对比 overflow: hidden 的副作用。
  2. 写一个"父级 transform 导致 z-index 失效"的例子,并修复。
  3. 用 Grid 的 auto-fit + minmax 实现自适应卡片网格。

② 让 AI 写同一题

把第 2 题(页面布局)交给 AI,补一句 不要用绝对定位硬摆,说明为什么选 flex 或 grid。

③ 对比要盯的点

  • 它选 flex 还是 grid?理由是内容驱动还是布局驱动?
  • 外边距折叠了解吗?父子、兄弟折叠的规则与 BFC 的修法。
  • 移动端 100vh 它有没有处理?浏览器地址栏会导致溢出。

④ 一句话取舍

它这套布局在 320px 宽的老手机上会怎样?

九、自测

  1. content-box 与 border-box 的差异?
  2. BFC 能解决哪三类问题?
  3. 哪些属性会创建层叠上下文?
  4. Flex 与 Grid 的选择标准?
  5. 容器查询与媒体查询的区别?

参考答案要点:宽度是否含内边距;塌陷/折叠/环绕;定位+z-index、opacity、transform;一维 vs 二维;父容器 vs 视口。

附录:高频追问

问:margin 折叠发生在什么情况? 相邻兄弟、父子(无内边距/边框/内容分隔)、空元素自身;BFC 可以阻止父子折叠。

问:position: sticky 不生效? 常见原因是祖先有 overflow: hidden/auto,或没有设置 top 等阈值。

问:1fr 为什么会被撑破? 1fr 的最小值是 auto,内容过宽会撑开;用 minmax(0, 1fr) 限制。

问:z-index 负值有用吗? 有,但在同一层叠上下文内,可能被父级背景遮挡,慎用。

问:Flex 的 flex: 1 等价于什么? flex-grow: 1; flex-shrink: 1; flex-basis: 0%,注意 basis 是 0 而不是 auto。

问:Grid 能替代 Flex 吗? 不能。一维布局 Flex 更简单,二维布局 Grid 更直接,实际项目常混用。

问:如何做响应式字体? 用 clamp() 设置最小、首选、最大值,避免媒体查询堆叠。

问:will-change: transform 有什么风险? 长期占用合成层与显存,动画结束应移除。

布局的计算成本

布局是从上到下的几何计算,成本与节点数量、嵌套深度、浮动/定位的复杂度相关。频繁触发布局的写法,在低端设备上会被放大。

降低布局成本的手段:减少 DOM 数量、避免深层嵌套、用 contain: layout 隔离子树、把动画放到 transform。

三栏布局的演进

  • 浮动 + 负 margin:兼容老浏览器,但难以维护。
  • Flex:中间自适应,两侧固定,代码短。
  • Grid:grid-template-columns: 200px 1fr 200px,语义最清晰。

面试时讲清“为什么从浮动演进到 Grid”,比背三套代码更能体现理解。

居中的四种写法

方式写法适用
Flexjustify-content + align-items未知尺寸,最稳
Gridplace-items: center父级为 grid 时最简
绝对定位 + transformleft:50%; top:50%; transform:translate(-50%,-50%)脱离文档流
margin auto固定宽高 + margin:auto块级元素

能用 Flex/Grid 就不用绝对定位,后者需要知道尺寸且影响文档流。

移动端 1px 与安全区

1px 边框在高倍屏会显示成 2-3 物理像素,常见解法是用伪元素 + transform: scaleY(0.5)。刘海屏用 env(safe-area-inset-*) 给底部与顶部留出安全区,避免被遮挡。

移动端还要注意 300ms 点击延迟、滚动穿透与输入框被键盘顶起,这些都不是“CSS 写得好”能解决的,需要配合 JS 与视口设置。

逻辑属性与书写方向

国际化项目用逻辑属性替代方向属性:margin-inline、padding-block、inset-inline-start。它们在 LTR 与 RTL 下自动镜像,不用写两套样式。

判断标准:如果页面要支持阿拉伯语或希伯来语,一开始就用逻辑属性,后期改造成本很高。

选择器性能

浏览器匹配选择器从右往左,过深的后代选择器与通配符会增加匹配成本。但样式匹配通常不是瓶颈,布局与绘制才是;先修布局,再谈选择器。先布局,后选择器;结构决定成本,少一层嵌套,少一分成本。先结构,后样式。先结构,再样式。

配套题目

★ 越多越该先背;点题目可看完整答案与深入版。

提示:读完可以顺手做几道对应题目,检验是否真的理解