created: 2026-06-13
tags: css, 布局, 面试, 零基础
CSS 布局 ------ 把元素放到正确的位置
学习前提:你已经知道 CSS 基础(选择器、盒模型、display),现在要学的是------怎么把元素摆到页面上你想要的位置。
1. Flexbox(面试必考,最高优先级)
Flexbox 是啥?先打比方
类比 :想象你有一个托盘 (flex 容器),上面放了几个碗(flex 项目)。
┌───┬───┬───┐
│ 碗1 │ 碗2 │ 碗3 │
└───┴───┴───┘
Flexbox 就是用来控制这些"碗"在"托盘"上怎么排列的:
- 从左到右排?还是从上到下排?
- 靠左?靠右?居中?
- 空间不够了怎么办?缩小还是换行?
- 某个碗特别大,怎么分配空间?
一句话总结 :Flexbox 是一种一维 布局系统,它只关心一行 或者一列(不能同时控制行和列)。
面试重点 :Flexbox 是前端面试最高频的 CSS 考点,几乎每一场面试都会问。
先看一个最简单的例子
html
<div style="display: flex;">
<div style="padding: 10px; background: red;">1</div>
<div style="padding: 10px; background: green;">2</div>
<div style="padding: 10px; background: blue;">3</div>
</div>
效果 :三个本来应该竖着堆叠的 div(因为 block 元素默认独占一行),现在横着排成了一行!
人话 :加了 display: flex 后,父元素就变成了"灵活容器",里面的子元素默认从左到右横着排列。
容器属性(写在父元素上)
flex-direction ------ 决定排列方向
css
.container {
display: flex;
flex-direction: row; /* 默认值:从左到右横着排 */
}
| 值 | 效果 | 人话 |
|---|---|---|
row(默认) |
→ 从左到右 | 横着排 |
row-reverse |
← 从右到左 | 横着反过来排 |
column |
↓ 从上到下 | 竖着排 |
column-reverse |
↑ 从下到上 | 竖着反过来排 |
css
/* 竖着排列 */
.container {
display: flex;
flex-direction: column;
}
/* 效果:子元素从上到下排列,恢复成block的竖排效果 */
justify-content ------ 主轴方向的对齐(面试必考)
先搞懂"主轴"是哪个方向:
- 当
flex-direction: row时,主轴 = 水平方向(从左到右) - 当
flex-direction: column时,主轴 = 垂直方向(从上到下)
justify-content 控制元素在主轴方向怎么排列。
css
.container {
display: flex;
/* flex-direction: row 时,justify-content 控制水平排列 */
}
css
/* 靠左排列(默认) */
.container { justify-content: flex-start; }
/* ┌──┬──┬──┐ */
/* │1 │2 │3 │ */
/* └──┴──┴──┘ */
css
/* 靠右排列 */
.container { justify-content: flex-end; }
/* ┌──┬──┬──┐ */
/* │1 │2 │3 │ */
/* └──┴──┴──┘ */
css
/* 居中排列 */
.container { justify-content: center; }
/* ┌──┬──┬──┐ */
/* │1 │2 │3 │ */
/* └──┴──┴──┘ */
css
/* 两端对齐:第一个靠左,最后一个靠右,中间均匀分布 */
.container { justify-content: space-between; }
/* ┌──┬──────┬──┬──────┬──┐ */
/* │1 │ │2 │ │3 │ */
/* └──┴──────┴──┴──────┴──┘ */
css
/* 每个元素左右空间相等 */
.container { justify-content: space-around; }
/* ┌──┬──┬──┬──┬──┬──┐ */
/* │1 │ │2 │ │3 │ │ */
/* └──┴──┴──┴──┴──┴──┘ */
css
/* 完全等距 */
.container { justify-content: space-evenly; }
/* ┌──┬──┬──┬──┬──┬──┐ */
/* │1 │ │2 │ │3 │ │ */
/* └──┴──┴──┴──┴──┴──┘ */
人话总结 :justify-content 就像在架子上摆碗 ------ 你想挤在左边、右边、中间,还是均匀散开。
面试重点 :
justify-content: center是实现水平居中的关键,要记住!
align-items ------ 交叉轴方向的对齐
交叉轴 = 和主轴垂直的方向:
- 如果主轴是水平的(row),交叉轴就是垂直的
- 如果主轴是垂直的(column),交叉轴就是水平的
css
.container {
display: flex;
height: 200px; /* 给个高度才能看到效果 */
}
css
/* 拉伸填满(默认)------ 子元素高度自动拉伸到和父容器一样高 */
.container { align-items: stretch; }
css
/* 靠上对齐 */
.container { align-items: flex-start; }
css
/* 靠下对齐 */
.container { align-items: flex-end; }
css
/* 垂直居中(超重要!) */
.container { align-items: center; }
人话总结 :align-items 控制元素在垂直方向的位置(当 flex-direction 为 row 时)。
面试重点 :
justify-content: center+align-items: center= 水平垂直居中,面试必考题!
flex-wrap ------ 换不换行
css
.container {
display: flex;
flex-wrap: nowrap; /* 默认:不换行,所有项目挤在一行 */
}
假设容器宽 300px,每个项目宽 100px,一共 4 个项目:
nowrap(默认):4 × 100 = 400 > 300,项目会被压缩到一行里wrap:超出的项目会换到下一行,变成 3 个一行 + 1 个在第二行wrap-reverse:换行,但新行在上方
css
.container {
display: flex;
flex-wrap: wrap; /* 自动换行 */
}
.item {
width: 100px;
height: 100px;
}
常见坑 :不加 flex-wrap: wrap,子元素会被压缩到一行,看着变形了。做了响应式布局一定要加 flex-wrap: wrap。
gap ------ 项目之间的间距
css
.container {
display: flex;
flex-wrap: wrap;
gap: 20px; /* 项目之间上下左右都是 20px 间距 */
/* row-gap: 20px; 只控制行的间距 */
/* column-gap: 20px; 只控制列的间距 */
}
人话 :gap 就是在项目之间"插入"固定的空隙。和 margin 的区别是:gap 只在项目之间加,不在边缘加。
常见坑 :以前没有
gap时,大家用margin+ 各种 hack。现在直接用gap,干净利落。
项目属性(写在子元素上)
flex ------ 缩写(面试必考)
flex 是三个属性的缩写:flex-grow(放大) | flex-shrink(缩小) | flex-basis(初始大小)
最常见的用法:flex: 1
css
.item {
flex: 1;
}
/* 等价于:
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0%; */
人话 :flex: 1 的意思是"把剩下的空间都给我"。
举个栗子:
html
<div style="display: flex; width: 600px;">
<div style="flex: 1; background: red;">1</div>
<div style="flex: 2; background: green;">2</div>
<div style="flex: 1; background: blue;">3</div>
</div>
怎么分空间?
- 3 个项目的 flex 分别是 1、2、1,总和 = 4
- 600px 分成 4 份,每份 = 150px
- 红 = 150px,绿 = 300px,蓝 = 150px
人话 :flex 的数字就像"分蛋糕的比例"。flex:1 分 1 份,flex:2 分 2 份。
等宽布局
css
.item {
flex: 1; /* 所有 item 都写 flex:1,宽度就一样了 */
}
固定侧边栏 + 自适应内容
css
.layout {
display: flex;
}
.sidebar {
width: 200px;
flex-shrink: 0; /* 禁止缩小 ------ 永远保持200px */
}
.main {
flex: 1; /* 占据剩下的所有空间 */
}
面试重点 :给一个容器,里面三个项目,
flex: 1/flex: 2/flex: 1,问各占多少比例 ------ 常见面试题。
align-self ------ 单独"不听话"的项目
css
.container {
display: flex;
height: 200px;
align-items: flex-start; /* 其他项目都靠上 */
}
.special {
align-self: center; /* 偏偏我要居中 */
}
人话 :align-items 是给所有项目设置的"统一规则",align-self 允许某个项目"不听话",单独给自己设置一个对齐方式。
order ------ 改变视觉顺序
css
.item1 { order: 2; }
.item2 { order: 1; } /* 这个反而排到前面去了 */
.item3 { order: 3; }
人话 :不改变 HTML 结构,只改变显示顺序。默认所有项目 order: 0,数字小的排前面。
Flexbox 经典布局(面试常考)
1. 水平垂直居中(面试最爱,必须会!)
css
.parent {
display: flex;
justify-content: center; /* 水平居中 */
align-items: center; /* 垂直居中 */
height: 300px; /* 父容器要有高度才能垂直居中 */
}
html
<div class="parent" style="border: 1px solid black;">
<div style="background: red; padding: 20px;">我居中啦!</div>
</div>
效果:红色块在父容器正中央,不多不少刚刚好。
面试重点:几乎所有面试都会问"如何让一个元素水平垂直居中",flexbox 方案是第一回答。
2. 粘性底部(Sticky Footer)
需求:不管内容多还是少,footer 永远在页面底部。
html
<body>
<header>Header</header>
<main>内容区域(内容少时,footer也在底部)</main>
<footer>Footer</footer>
</body>
css
body {
display: flex;
flex-direction: column; /* 从上到下排列 */
min-height: 100vh; /* 至少占满整个屏幕高度 */
margin: 0; /* 去掉body默认的外边距 */
}
main {
flex: 1; /* 自动撑满剩余空间,把footer推到底部 */
}
footer {
height: 60px;
background: #333;
color: white;
text-align: center;
}
人话 :main 区域的 flex: 1 就像一个可伸缩的弹簧 ------ 内容少时它就伸长撑满空间,内容多时它自动压缩。
3. 等距卡片(网格)
css
.container {
display: flex;
flex-wrap: wrap; /* 允许换行 */
gap: 16px; /* 卡片间距 */
}
.card {
flex: 1 1 300px; /* grow:1 shrink:1 basis:300px */
/* 人话:每个卡片至少300px宽,空间多了就长大,空间少了就缩小,不够就换行 */
}
2. Grid(二维布局)
Flexbox vs Grid:一个经典类比
| Flexbox | Grid | |
|---|---|---|
| 维度 | 一维(行或列) | 二维(行和列同时控制) |
| 思路 | 内容优先 ------ "这些项目怎么排" | 布局优先 ------ "我先画个网格,再把项目放进去" |
| 最佳场景 | 导航栏、列表、居中、小部件排列 | 整个页面的骨架、复杂的二维排列 |
人话:
- Flexbox:你有一排东西,告诉它们怎么在这一排 或这一列里排列
- Grid:你画了一张表格 ,把东西方到对应的 格子 里
Grid 基础
css
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr; /* 3列,每列等宽 */
gap: 10px;
}
html
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
效果:6 个项目排成 2 行 3 列,像表格一样整整齐齐。
fr ------ 分数单位
css
/* 3列等宽 */
.container { grid-template-columns: 1fr 1fr 1fr; }
css
/* 左侧200px,右侧占剩余空间 */
.container { grid-template-columns: 200px 1fr; }
css
/* 三列,中间是内容区,左右固定 */
.container { grid-template-columns: 200px 1fr 200px; }
人话 :fr = fraction(分数),就像 flexbox 里的 flex: 1,按比例分配剩余空间。
repeat() ------ 重复简写
css
/* 下面两种写法一样 */
.container { grid-template-columns: 1fr 1fr 1fr; }
.container { grid-template-columns: repeat(3, 1fr); } /* 重复3次1fr */
Grid 区域命名 ------ 最直观的布局方式
css
.layout {
display: grid;
grid-template-columns: 200px 1fr; /* 两列:左200px,右自适应 */
grid-template-rows: auto 1fr auto; /* 三行:头、内容、脚 */
grid-template-areas:
"header header" /* 第一行:header占两列 */
"sidebar main" /* 第二行:sidebar左列,main右列 */
"footer footer"; /* 第三行:footer占两列 */
gap: 10px;
min-height: 100vh;
}
/* 把对应的区域名字写在元素上 */
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }
html
<div class="layout">
<header class="header">Header</header>
<aside class="sidebar">Sidebar</aside>
<main class="main">Main Content</main>
<footer class="footer">Footer</footer>
</div>
效果:
┌──────────────────────────────┐
│ Header │ ← 横跨两列
├─────────┬────────────────────┤
│ Sidebar │ Main Content │
│ 200px │ │
├─────────┴────────────────────┤
│ Footer │ ← 横跨两列
└──────────────────────────────┘
人话 :用 grid-template-areas 就像画座位表 ------ 你告诉 Grid "第一排两个位置给 header,第二排左边给 sidebar 右边给 main",然后每个元素报自己的名字就行。
面试重点:Grid 区域命名做页面骨架布局(圣杯布局),清晰直观,面试时能用上就是加分项。
3. 响应式设计
核心思想:同一个页面在不同屏幕上都好看
在手机上竖着排,在电脑上横着排 ------ 这就是响应式。
媒体查询(Media Query)
css
/* 默认样式(桌面端优先) */
.container {
display: flex;
flex-direction: row; /* 横着排 */
}
/* 当屏幕宽度小于等于 768px 时(平板、手机) */
@media (max-width: 768px) {
.container {
flex-direction: column; /* 改为竖着排 */
}
}
语法拆解:
css
@media (max-width: 768px) {
/* 条件:屏幕宽度 ≤ 768px 时,花括号里的CSS生效 */
/* 这个就叫"断点"(breakpoint) */
}
常见断点:
css
/* 手机:< 480px */
@media (max-width: 480px) { ... }
/* 平板:481px ~ 768px */
@media (max-width: 768px) { ... }
/* 小桌面:769px ~ 1024px */
@media (max-width: 1024px) { ... }
/* 大桌面:> 1024px ------ 默认样式 */
响应式单位
css
.text {
font-size: 16px; /* 固定大小,不会随着屏幕变化 */
font-size: 1rem; /* 基于根元素字号,推荐 */
}
.box {
width: 50%; /* 父容器的一半宽 */
height: 50vh; /* 视口高度的一半 */
}
.full-screen {
width: 100vw; /* 铺满视口宽 */
height: 100vh; /* 铺满视口高 */
}
移动端必加的一行
html
<meta name="viewport" content="width=device-width, initial-scale=1.0">
人话:这行代码告诉手机浏览器:"别自作主张缩放页面,按设备的真实宽度显示"。不加的话,手机浏览器会把 980px 宽的页面缩成手机屏幕大小,字就变得很小。
4. 面试经典布局题
题目 1:水平垂直居中(至少会 3 种方法!)
css
/* 方法1:Flexbox(最推荐,一行搞定) */
.parent {
display: flex;
justify-content: center;
align-items: center;
}
css
/* 方法2:absolute + transform(万能居中) */
.parent {
position: relative; /* 给子元素做参考 */
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* 把自己往回挪一半 */
}
/* 人话:先让左上角在正中间,再把自己往左上方拽自身宽高的一半 */
css
/* 方法3:Grid(最简洁) */
.parent {
display: grid;
place-items: center; /* 一个属性搞定水平和垂直居中 */
}
面试重点:面试官问"如何居中",至少说出 flexbox 和 absolute+transform 两种。
题目 2:两栏布局(左侧固定,右侧自适应)
css
/* Flexbox 方法 */
.container {
display: flex;
}
.sidebar {
width: 200px;
flex-shrink: 0; /* 禁止缩小 */
}
.main {
flex: 1; /* 占满剩余空间 */
}
html
<div class="container">
<aside class="sidebar">侧边栏 200px</aside>
<main class="main">主内容区域,自动撑满</main>
</div>
效果:
┌──────────┬────────────────────────────────┐
│ Sidebar │ Main │
│ 200px │ 自适应 │
└──────────┴────────────────────────────────┘
题目 3:圣杯布局(Header + 左右三栏 + Footer)
html
<div class="layout">
<header class="header">Header</header>
<div class="main-content">
<nav class="left">Left Sidebar</nav>
<article class="center">Main Content</article>
<aside class="right">Right Sidebar</aside>
</div>
<footer class="footer">Footer</footer>
</div>
Flexbox 方案:
css
.layout {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.main-content {
display: flex;
flex: 1; /* 撑满中间区域 */
}
.left, .right {
width: 200px;
flex-shrink: 0; /* 固定宽度不缩小 */
}
.center {
flex: 1; /* 中间自适应 */
}
.footer {
height: 60px;
}
效果:
┌──────────────────────────────────┐
│ Header │
├────────┬─────────────┬───────────┤
│ Left │ Center │ Right │
│ 200px │ 自适应 │ 200px │
├────────┴─────────────┴───────────┤
│ Footer │
└──────────────────────────────────┘
题目 4:等距卡片网格
css
/* Flexbox 方案 */
.container {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.card {
flex: 1 1 300px; /* 最小 300px,占1份,可缩小 */
/* 或使用 calc */
flex: 1 1 calc(33.33% - 16px); /* 每行3列,减去gap */
}
css
/* Grid 方案(更整齐!) */
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
}
/* 每一列最少250px,自动填满,最后一行不会留白 */
5. 练习:做一个响应式页面
要求:用 flexbox 实现以下布局,并在手机屏幕(< 768px)时变成上下排列。
html
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/* 在这里写 CSS */
</style>
</head>
<body>
<header class="header">
<h1>我的网站</h1>
<nav>
<a href="#">首页</a>
<a href="#">关于</a>
<a href="#">联系</a>
</nav>
</header>
<main class="main">
<aside class="sidebar">
<h3>侧边栏</h3>
<ul>
<li>分类1</li>
<li>分类2</li>
<li>分类3</li>
</ul>
</aside>
<article class="content">
<h2>文章标题</h2>
<p>这是文章内容。这是文章内容。这是文章内容。这是文章内容。</p>
<p>更多内容......</p>
</article>
</main>
<footer class="footer">
<p>© 2025 我的网站</p>
</footer>
</body>
</html>
要求:
- header 和 footer 横跨全屏,有背景色,白色文字
- main 区域用 flexbox:左侧 sidebar 200px,右侧 content 自适应
- footer 固定在底部(sticky footer)
- 页面最小高度占满屏幕
提示:
css
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.header {
display: flex; /* 让标题和导航在一行 */
justify-content: space-between;
align-items: center;
background: #333;
color: white;
padding: 16px;
}
.main {
display: flex;
flex: 1; /* 撑满中间区域 */
}
.sidebar {
width: 200px;
flex-shrink: 0;
background: #f0f0f0;
padding: 16px;
}
.content {
flex: 1;
padding: 16px;
}
.footer {
background: #333;
color: white;
text-align: center;
padding: 16px;
}
/* 响应式:手机端变上下排列 */
@media (max-width: 768px) {
.main {
flex-direction: column;
}
.sidebar {
width: 100%; /* 侧边栏占满宽度 */
}
}
预期效果(桌面端 > 768px):
┌──────────────────────────────────────┐
│ 我的网站 首页 关于 联系 │
├────────────┬─────────────────────────┤
│ 侧边栏 │ 文章标题 │
│ 分类1 │ 文章内容...... │
│ 分类2 │ │
│ 分类3 │ │
├────────────┴─────────────────────────┤
│ © 2025 我的网站 │
└──────────────────────────────────────┘
预期效果(移动端 < 768px):
┌──────────────────┐
│ 我的网站 │
│ 首页 关于 联系 │
├──────────────────┤
│ 文章标题 │
│ 文章内容...... │
├──────────────────┤
│ 侧边栏 │
│ 分类1 分类2 分类3│
├──────────────────┤
│ © 2025 我的网站│
└──────────────────┘
完成了这个练习,你就掌握了前端面试中最核心的布局技能。