CSS 布局
发表于:2026-07-29
字数统计:9000 字
预计阅读31分钟
涵盖 BFC、圣杯布局、双飞翼布局、三栏布局(5 种方案)、居中布局(8 种方案)、Flex 完整指南、Grid 完整指南、瀑布流、响应式。
一、BFC(Block Formatting Context)
1. 什么是 BFC
BFC(块级格式化上下文)是 CSS 渲染过程的一块独立区域,区域内的元素布局不会影响外部,外部也不会影响内部。
2. 触发 BFC
CSS
/* 以下方式都会创建 BFC */
.float { float: left; } /* 浮动 */
.ofh { overflow: hidden; } /* overflow 不为 visible */
.abs { position: absolute; } /* 绝对定位 */
.fix { position: fixed; } /* 固定定位 */
.flex { display: flex; } /* flex 容器 */
.grid { display: grid; } /* grid 容器 */
.inline-block { display: inline-block; } /* 行内块 */
.table { display: table; } /* 表格 */
.cell { display: table-cell; } /* 表格单元格 */
.flow-root { display: flow-root; } /* 显式 BFC(推荐) */
.html { html 本身; } /* html 根元素 */3. BFC 的特性与作用
CSS
/* 特性 1:内部 box 在垂直方向一个接一个放置 */
.bfc {
display: flow-root; /* 创建 BFC */
/* 子元素垂直排列 */
}
/* 特性 2:垂直方向的距离由 margin 决定,属于同一个 BFC 的相邻 box 的 margin 会重叠(margin 折叠) */
/* 特性 3:BFC 区域不会与浮动 box 重叠(实现两栏布局) */
.container {
display: flow-root;
/* 利用 BFC 不会与浮动元素重叠的特性 */
}
/* 特性 4:BFC 计算高度时包括浮动元素(清除浮动) */
.container {
display: flow-root;
/* 浮动的子元素会被计入高度 */
}
/* 特性 5:BFC 是独立的容器,内部元素不会影响外部 */4. BFC 应用场景
HTML
<!-- 场景 1:清除浮动(父元素高度塌陷) -->
<style>
.parent { display: flow-root; }
.child { float: left; height: 100px; }
</style>
<div class="parent">
<div class="child"></div>
</div>
<!-- 父元素高度 = 子元素高度,塌陷解决 -->
<!-- 场景 2:避免 margin 折叠 -->
<style>
.box { margin: 20px 0; }
.wrapper { display: flow-root; }
</style>
<div class="wrapper">
<div class="box">上 margin 20</div>
</div>
<div class="wrapper">
<div class="box">上 margin 20(不会与上一个叠加)</div>
</div>
<!-- 场景 3:实现两栏布局 -->
<style>
.left { float: left; width: 200px; background: red; }
.right { display: flow-root; background: blue; }
</style>
<div class="left"></div>
<div class="right">右栏</div>
<!-- right 是 BFC,不会被 left 覆盖 -->二、常见布局方案
1. 居中布局
水平居中
CSS
/* 1. inline 元素:text-align */
.parent { text-align: center; }
.child { display: inline-block; }
/* 2. block 元素 + 定宽:margin auto */
.child { width: 200px; margin: 0 auto; }
/* 3. block 元素 + 不定宽:display flex(推荐) */
.parent { display: flex; justify-content: center; }
/* 4. 绝对定位 + transform(不需定宽) */
.child { position: absolute; left: 50%; transform: translateX(-50%); }垂直居中
CSS
/* 1. 单行行内元素:line-height */
.parent { height: 100px; line-height: 100px; }
.child { display: inline-block; }
/* 2. 多行行内元素:display table-cell + vertical-align */
.parent { display: table-cell; vertical-align: middle; height: 100px; }
/* 3. block + 定高:绝对定位 + 负 margin */
.child {
position: absolute;
top: 50%;
height: 50px;
margin-top: -25px;
}
/* 4. block + 不定高:flex(推荐) */
.parent {
display: flex;
align-items: center;
height: 100px;
}
/* 5. 绝对定位 + transform */
.child {
position: absolute;
top: 50%;
transform: translateY(-50%);
}水平垂直居中
CSS
/* 1. flex(最常用) */
.parent {
display: flex;
justify-content: center;
align-items: center;
}
/* 2. grid */
.parent {
display: grid;
place-items: center;
}
/* 3. 绝对定位 + transform */
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
/* 4. 绝对定位 + margin auto */
.child {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
margin: auto;
width: 200px;
height: 100px;
}2. 三栏布局(5 种方案)
方案 1:float + margin(经典)
CSS
.left, .right { float: left; width: 200px; }
.center { margin: 0 200px; }
/* ⚠️ 问题:center 区域内容会被浮动遮挡,且需要清浮动 */方案 2:float + BFC
CSS
.left { float: left; width: 200px; }
.right { float: right; width: 200px; }
.center { display: flow-root; margin: 0 200px; }
/* ✅ center 形成 BFC,不会被浮动遮挡 */方案 3:position 绝对定位
CSS
.parent { position: relative; }
.left, .right { position: absolute; top: 0; width: 200px; }
.left { left: 0; }
.right { right: 0; }
.center { margin: 0 200px; }
/* ⚠️ 高度需要随中间内容自适应 */方案 4:table 布局
CSS
.parent { display: table; width: 100%; }
.left, .center, .right { display: table-cell; }
.left, .right { width: 200px; }
/* ✅ 高度自动对齐,缺点是 table 语义差 */方案 5:flex(推荐)
CSS
.parent { display: flex; }
.left, .right { width: 200px; flex: 0 0 200px; }
.center { flex: 1; }
/* ✅ 简单、灵活、自适应 */方案 6:grid(最强大)
CSS
.parent {
display: grid;
grid-template-columns: 200px 1fr 200px;
}
/* ✅ 代码最少,能力最强 */3. 圣杯布局(Holy Grail Layout)
三栏布局的变种:左右固定宽度,中间先渲染(HTML 中位置在前)。
HTML
<div class="container">
<div class="center">中间</div>
<div class="left">左</div>
<div class="right">右</div>
</div>CSS
/* 关键思路:用 float + 负 margin 把左右栏拉到中间行 */
.container {
padding: 0 200px; /* 给左右栏留出空间 */
overflow: hidden;
}
.center, .left, .right {
float: left;
position: relative;
}
.center { width: 100%; }
.left { width: 200px; margin-left: -100%; left: -200px; }
.right { width: 200px; margin-left: -200px; right: -200px; }
/* ⚠️ 问题:min-width 有限制(最小宽度 = 左 + 右 + 中间),窗口太小时会乱 */4. 双飞翼布局
HTML
<div class="container">
<div class="center-wrap">
<div class="center">中间</div>
</div>
<div class="left">左</div>
<div class="right">右</div>
</div>CSS
.container { overflow: hidden; }
.center-wrap, .left, .right { float: left; }
.center-wrap { width: 100%; }
.center { margin: 0 200px; }
.left { width: 200px; margin-left: -100%; }
.right { width: 200px; margin-left: -200px; }
/* 优势:没有 min-width 问题,比圣杯更稳健 */5. 瀑布流布局
CSS
/* 方法 1:CSS columns */
.waterfall {
column-count: 3;
column-gap: 16px;
}
.waterfall-item {
break-inside: avoid;
margin-bottom: 16px;
}
/* 方法 2:JS 计算定位(更精确) */
.waterfall-item {
position: absolute;
}
/* JS:根据图片高度计算每列的位置 */三、Flex 布局完整指南
1. 容器属性
CSS
.container {
display: flex; /* 启用 flex */
/* 主轴方向 */
flex-direction: row | row-reverse | column | column-reverse;
/* 换行 */
flex-wrap: nowrap | wrap | wrap-reverse;
/* 主轴对齐 */
justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
/* 交叉轴对齐(单行) */
align-items: stretch | flex-start | flex-end | center | baseline;
/* 多行对齐 */
align-content: stretch | flex-start | flex-end | center | space-between | space-around;
}2. 子项属性
CSS
.item {
order: 0; /* 排序,数字小的在前 */
flex-grow: 0; /* 放大比例,0 不放大 */
flex-shrink: 1; /* 缩小比例,1 可缩小 */
flex-basis: auto; /* 初始大小 */
flex: 0 1 auto; /* grow shrink basis 简写 */
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}3. 常用布局
CSS
/* 1. 居中(最常用) */
.container { display: flex; justify-content: center; align-items: center; }
/* 2. 左右分布 */
.container { display: flex; justify-content: space-between; }
/* 3. 一行操作按钮 */
.toolbar { display: flex; gap: 8px; }
/* 4. 自适应中间 */
.left { flex: 0 0 200px; }
.center { flex: 1; }
.right { flex: 0 0 200px; }
/* 5. 垂直布局 */
.column { display: flex; flex-direction: column; }
/* 6. 文本溢出省略 */
.flex-ellipsis { display: flex; }
.flex-ellipsis .text {
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}四、Grid 布局完整指南
1. 基础概念
CSS
.container {
display: grid;
/* 定义行高 */
grid-template-rows: 100px 200px auto;
/* 定义列宽 */
grid-template-columns: 200px 1fr 200px;
/* 间距 */
gap: 16px; /* row-gap + column-gap */
row-gap: 16px;
column-gap: 16px;
}2. 命名网格
CSS
.container {
display: grid;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }3. 函数式定义
CSS
.container {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 列等宽 */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* 自适应列数 */
grid-template-columns: 200px 1fr 200px; /* 显式三列 */
}
.item {
grid-column: 1 / 3; /* 跨第 1~3 列 */
grid-row: 1 / 2; /* 第 1 行 */
/* 简写:grid-row-start / grid-row-end */
grid-area: 1 / 1 / 2 / 3; /* row-start / col-start / row-end / col-end */
}4. 实用模板
CSS
/* 经典管理后台布局 */
.app-layout {
display: grid;
grid-template-areas:
"header header"
"sidebar main"
"footer footer";
grid-template-rows: 60px 1fr 40px;
grid-template-columns: 200px 1fr;
height: 100vh;
}
/* 自适应卡片 */
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
}
/* 等高布局(grid 天然支持) */
.row {
display: grid;
grid-template-columns: repeat(3, 1fr);
/* 子项高度自动相同 */
}5. Flex vs Grid 选择
| 场景 | 推荐 |
|---|---|
| 一维布局(一行或一列) | Flex |
| 二维布局(行列同时控制) | Grid |
| 内容驱动(项目大小决定布局) | Flex |
| 布局驱动(先有容器骨架) | Grid |
| 微调(间距、居中、对齐) | Flex |
| 复杂页面骨架 | Grid |
五、响应式布局
1. 媒体查询
CSS
/* 移动优先写法 */
.container { font-size: 14px; }
@media (min-width: 768px) {
.container { font-size: 16px; }
}
@media (min-width: 1024px) {
.container { font-size: 18px; }
}2. 响应式图片
CSS
img {
max-width: 100%;
height: auto;
}
/* art direction:不同屏幕用不同图片 */
@media (max-width: 600px) {
.hero-img { content: url('mobile.jpg'); }
}
@media (min-width: 601px) {
.hero-img { content: url('desktop.jpg'); }
}3. 容器查询(Container Queries)
CSS
.card-container {
container-type: inline-size;
container-name: card;
}
@container card (min-width: 400px) {
.card { display: flex; }
.card-image { flex: 0 0 200px; }
}
@container card (max-width: 399px) {
.card { display: block; }
}4. 自适应单位
CSS
/* rem:相对 html 字号 */
html { font-size: 16px; }
.box { width: 10rem; } /* 160px */
/* vw/vh:相对视口 */
.hero { width: 100vw; height: 100vh; }
.box { font-size: 4vw; }
/* clamp:响应式字号 */
.title {
font-size: clamp(1rem, 2vw + 1rem, 3rem);
/* 最小 1rem,最大 3rem,介于中间随视口缩放 */
}六、面试高频问答
Q1: 什么是 BFC?有什么用?
答:BFC(块级格式化上下文)是 CSS 渲染过程的一块独立区域。触发方式包括 float(除 none)、overflow(除 visible)、position(absolute/fixed)、display(flex/grid/inline-block/table-cell/flow-root)等。
BFC 的核心作用:
- 清除浮动:BFC 计算高度时包含浮动元素(解决父元素高度塌陷)
- 避免 margin 折叠:相邻元素不属于同一 BFC 时不会发生 margin 折叠
- 防止被浮动覆盖:BFC 区域不会与浮动 box 重叠(实现两栏布局)
Q2: 三栏布局有几种实现方式?优缺点?
答:常见 5 种:
| 方案 | 优点 | 缺点 |
|---|---|---|
| float + margin | 兼容性好 | 需要清浮动,中间内容可能遮挡 |
| float + BFC | 不被遮挡 | 兼容性 OK |
| position 绝对 | 简单 | 高度不自适应 |
| table 布局 | 高度自动对齐 | table 语义差 |
| flex | 简单灵活 | 兼容性 IE 不支持 |
| grid | 代码最少 | 兼容性 IE 不支持 |
现代推荐 flex 或 grid。
Q3: 圣杯布局和双飞翼布局的区别?
答:
- 圣杯:用一个 container 包三栏,container 加左右 padding,左右栏用相对定位 + 负 margin 把位置拉到 padding 处。中间内容不需要额外包裹。
- 双飞翼:中间内容多包一层 wrapper,wrapper 占 100%,左右栏用负 margin 拉到两侧。中间内容位置靠 wrapper 的 margin 调整。
两者效果一致,都是三栏布局。双飞翼更稳健(不存在 min-width 问题),圣杯不需要嵌套。
Q4: Flex 和 Grid 怎么选?
答:
- Flex:一维布局(控制单方向),内容驱动,适合组件内微调
- Grid:二维布局(行列同时控制),布局驱动,适合页面整体骨架
实际项目通常组合使用:Grid 做页面骨架,Flex 做组件内布局。
Q5: 如何实现水平垂直居中?
答:常见 4 种:
- Flex(最常用):
display: flex; justify-content: center; align-items: center; - Grid:
display: grid; place-items: center; - 绝对定位 + transform(不需定宽):
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - 绝对定位 + margin auto(需定宽高):
position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto;