前言:你是否也被這些 Flex 問題折磨過?
“為什麼我用justify-content: center卻無法垂直居中?”
“align-items和align-content到底什麼時候生效?”
“設置了width: 200px,加了flex:1後怎麼沒用了?”
作為前端開發最常用的佈局方案,Flex(彈性佈局)以 “靈活” 著稱,但這份靈活也讓很多開發者陷入 “混亂”—— 核心原因是沒吃透 “主軸與交叉軸” 的邏輯,以及各屬性的適用場景。本文將從基礎概念到實戰案例,帶你徹底搞懂 Flex 佈局,從此告別 “試錯式調樣式”。
一、Flex 佈局基礎:先搞懂這兩個核心概念
在學習任何屬性前,必須先理清 Flex 佈局的 “骨架”——父元素(flex container) 和子元素(flex item) 的關係,以及最關鍵的主軸與交叉軸。
1.1 什麼是 Flex 佈局?
Flex(Flexible Box)即 “彈性佈局”,通過給父元素設置display: flex,讓其所有子元素自動成為 “彈性子元素”,從而實現靈活的排列、對齊和尺寸分配。
一句話總結:父元素控制 “整體排列規則”,子元素控制 “自身特殊表現”。
/\* 最簡單的Flex佈局示例 \*/
.parent {
display: flex; /\* 父元素開啓Flex佈局 \*/
width: 500px;
height: 300px;
background: #f5f5f5;
}
.child {
width: 100px;
height: 100px;
background: #42b983;
margin: 10px;
}
效果:3 個child會自動沿水平方向排列(默認主軸方向),無需浮動或定位。
1.2 主軸與交叉軸:Flex 佈局的 “座標系”
這是最容易混淆的點!記住:所有 Flex 屬性都基於 “主軸” 和 “交叉軸”,而非固定的 “水平 / 垂直方向”。
- 主軸(main axis):子元素的排列方向,由
flex-direction決定(默認水平向左)。 - 交叉軸(cross axis):與主軸垂直的方向(默認垂直向下)。
舉個例子:當flex-direction: column(主軸設為垂直)時,原來的 “水平軸” 變成交叉軸,“垂直軸” 變成主軸 —— 此時justify-content(主軸對齊)控制垂直方向,align-items(交叉軸對齊)控制水平方向,這也是很多人 “垂直居中失效” 的根源!
核心口訣:先看flex-direction定主軸,再用對應屬性調對齊。
二、父元素的 6 個核心屬性:控制整體佈局
父元素的屬性決定了子元素的 “排列規則”,6 個屬性覆蓋 “方向、換行、對齊” 三大需求,每個屬性都有明確的適用場景。
2.1 flex-direction:決定主軸方向(子元素排列方向)
作用:定義主軸的方向,直接影響子元素的排列方向。
取值與效果:
| 取值 | 主軸方向 | 子元素排列效果 | 適用場景 |
|---|---|---|---|
| row(默認) | 水平向左 | 從左到右排列 | 導航欄、水平列表 |
| row-reverse | 水平向右 | 從右到左排列 | 反向導航、特殊排版 |
| column | 垂直向上 | 從上到下排列 | 表單、垂直列表、卡片組 |
| column-reverse | 垂直向下 | 從下到上排列 | 特殊垂直佈局(極少用) |
代碼演示(row vs column):
/\* 1. 水平排列(row):導航欄場景 \*/
.nav {
display: flex;
flex-direction: row; /\* 默認,可省略 \*/
justify-content: space-between; /\* 兩端對齊 \*/
padding: 0 20px;
background: #fff;
}
.nav-item {
padding: 10px;
}
/\* 2. 垂直排列(column):表單場景 \*/
.form {
display: flex;
flex-direction: column;
gap: 15px; /\* 子元素間距,Flex佈局常用 \*/
width: 300px;
}
.form-item {
display: flex;
flex-direction: row; /\* 子元素內部水平排列 \*/
gap: 10px;
}
一句話總結:水平佈局用row,垂直佈局用column,別搞反主軸方向!
2.2 flex-wrap:控制子元素是否換行
作用:當子元素總寬度 / 高度超過父元素時,是否換行(默認不換行,會壓縮子元素)。
取值與效果:
| 取值 | 效果 | 適用場景 |
|---|---|---|
| nowrap(默認) | 不換行,子元素會被壓縮 | 導航欄(不允許換行) |
| wrap | 換行,第一行在上 | 卡片網格、商品列表 |
| wrap-reverse | 換行,第一行在下 | 特殊排版(極少用) |
常見誤區:做卡片佈局時,忘記加flex-wrap: wrap,導致卡片被壓縮變形!
代碼演示(卡片網格):
.card-container {
display: flex;
flex-direction: row;
flex-wrap: wrap; /\* 關鍵:超出換行 \*/
gap: 20px;
padding: 20px;
background: #f5f5f5;
}
.card {
width: 200px; /\* 固定寬度 \*/
height: 300px;
background: #fff;
border-radius: 8px;
}
效果:當父元素寬度不足時,卡片自動換行,保持原有尺寸。
2.3 flex-flow:flex-direction + flex-wrap 的簡寫
作用:簡化代碼,將 “方向” 和 “換行” 合併設置,默認值row nowrap。
語法:flex-flow: <flex-direction> || <flex-wrap>
示例:
/\* 等價於 flex-direction: row; flex-wrap: wrap; \*/
.card-container {
display: flex;
flex-flow: row wrap;
gap: 20px;
}
2.4 justify-content:主軸上的對齊方式
作用:控制子元素在主軸方向上的對齊方式(水平或垂直,取決於flex-direction)。
取值與效果(以主軸為水平為例):
| 取值 | 效果 | 適用場景 |
|---|---|---|
| flex-start(默認) | 靠主軸起點對齊(左對齊) | 普通列表 |
| flex-end | 靠主軸終點對齊(右對齊) | 右側操作欄 |
| center | 主軸居中對齊 | 水平居中(如標題) |
| space-between | 兩端對齊,子元素間距相等 | 導航欄(兩端 logo + 菜單) |
| space-around | 子元素兩側間距相等(中間間距是邊緣 2 倍) | 均勻分佈的卡片 |
代碼演示(space-between 導航欄):
.nav {
display: flex;
flex-flow: row nowrap;
justify-content: space-between; /\* 兩端對齊 \*/
align-items: center; /\* 交叉軸居中(垂直居中) \*/
height: 60px;
padding: 0 20px;
background: #fff;
}
.nav-logo {
width: 100px;
}
.nav-menu {
display: flex;
gap: 20px;
}
效果:logo 在左,菜單在右,垂直居中對齊。
2.5 align-items:交叉軸上的單行對齊
作用:控制子元素在交叉軸方向上的對齊方式,僅對 “單行子元素” 生效(多行用align-content)。
取值與效果(以交叉軸為垂直為例):
| 取值 | 效果 | 適用場景 |
|---|---|---|
| stretch(默認) | 子元素高度佔滿父元素(需子元素無固定高度) | 卡片等高佈局 |
| flex-start | 靠交叉軸起點對齊(上對齊) | 頂部對齊的列表 |
| flex-end | 靠交叉軸終點對齊(下對齊) | 底部對齊的操作欄 |
| center | 交叉軸居中對齊(垂直居中) | 水平垂直居中(如彈窗) |
| baseline | 按子元素文字基線對齊 | 文字與圖標對齊 |
常見場景:水平垂直居中(面試高頻):
/\* 父元素:主軸水平,交叉軸垂直 \*/
.container {
display: flex;
justify-content: center; /\* 主軸(水平)居中 \*/
align-items: center; /\* 交叉軸(垂直)居中 \*/
width: 500px;
height: 300px;
background: #f5f5f5;
}
.child {
width: 100px;
height: 100px;
background: #42b983;
}
效果:child在container中完全居中,無需定位!
2.6 align-content:交叉軸上的多行對齊
作用:控制 “多行子元素” 在交叉軸上的對齊方式,單行子元素時無效(這是與align-items的核心區別)。
取值與效果(以交叉軸為垂直為例):
| 取值 | 效果 | 適用場景 |
|---|---|---|
| stretch(默認) | 多行高度佔滿父元素 | 多行卡片等高 |
| flex-start | 靠交叉軸起點對齊(上對齊) | 多行列表頂部對齊 |
| flex-end | 靠交叉軸終點對齊(下對齊) | 多行列表底部對齊 |
| center | 交叉軸居中對齊 | 多行內容整體居中 |
| space-between | 兩端對齊,行間距相等 | 均勻分佈的多行卡片 |
| space-around | 每行兩側間距相等 | 寬鬆的多行佈局 |
代碼演示(space-between 多行卡片):
.card-container {
display: flex;
flex-flow: row wrap;
align-content: space-between; /\* 多行垂直兩端對齊 \*/
width: 640px;
height: 600px; /\* 父元素固定高度,才有多行對齊效果 \*/
gap: 20px;
padding: 20px;
background: #f5f5f5;
}
.card {
width: 200px;
height: 250px;
background: #fff;
}
效果:兩行卡片分別靠頂部和底部對齊,中間間距自動分配。
align-items vs align-content 區別:
align-items:作用於 “單個子元素”,控制每行子元素的對齊;align-content:作用於 “所有行”,控制多行整體的對齊(單行無效)。
三、子元素的 6 個核心屬性:控制自身表現
子元素的屬性用於 “個性化調整”,比如改變排列順序、控制放大縮小、單獨對齊,解決 “特殊子元素” 的需求。
3.1 order:改變子元素的排列順序
作用:通過數值控制子元素的排列優先級,數值越小越靠前(默認 0)。
特點:無需修改 HTML 結構,僅通過 CSS 調整順序,適合動態佈局。
代碼演示(置頂通知):
.list {
display: flex;
flex-direction: column;
gap: 10px;
padding: 20px;
}
.list-item {
padding: 10px;
background: #fff;
}
/\* 通知項置頂(order=-1,比默認0小) \*/
.notice {
order: -1;
background: #fff3cd;
border: 1px solid #ffeeba;
}
效果:notice項會排在所有默認list-item前面。
3.2 flex-grow:控制子元素的放大比例
作用:當父元素有 “剩餘空間” 時,子元素的放大比例(默認 0,即不放大)。
規則:
- 所有子元素的
flex-grow總和為 1 時,按比例分配剩餘空間; - 若一個子元素
flex-grow:2,其他為 1,則它佔的剩餘空間是其他的 2 倍。
代碼演示(三欄佈局:中間自適應):
.layout {
display: flex;
width: 100%;
height: 500px;
gap: 20px;
}
/\* 左右欄固定寬度,不放大 \*/
.sidebar-left, .sidebar-right {
width: 200px;
flex-grow: 0; /\* 默認0,可省略 \*/
background: #fff;
}
/\* 中間欄自適應放大(佔滿剩餘空間) \*/
.main {
flex-grow: 1; /\* 剩餘空間全給中間 \*/
background: #fff;
}
效果:左右欄固定 200px,中間欄隨父元素寬度變化自適應。
3.3 flex-shrink:控制子元素的縮小比例
作用:當父元素 “空間不足” 時,子元素的縮小比例(默認 1,即會縮小)。
規則:
flex-shrink:0:子元素不縮小,會保持原尺寸(可能溢出父元素);- 所有子元素
flex-shrink:1:空間不足時等比例縮小。
常見場景(不縮小的圖片):
.card {
display: flex;
gap: 10px;
padding: 10px;
background: #fff;
width: 300px; /\* 父元素固定寬度 \*/
}
/\* 圖片不縮小(flex-shrink:0) \*/
.card-img {
width: 100px;
height: 100px;
flex-shrink: 0; /\* 關鍵:防止圖片被壓縮變形 \*/
object-fit: cover;
}
.card-content {
flex-grow: 1; /\* 內容區放大,佔滿剩餘空間 \*/
overflow: hidden; /\* 內容溢出時隱藏 \*/
}
效果:即使父元素寬度不足,圖片仍保持 100px,內容區會壓縮文字(或滾動)。
3.4 flex-basis:定義子元素的基準尺寸
作用:在分配剩餘空間前,子元素在主軸上的 “基準尺寸”(默認 auto,即子元素原尺寸)。
與 width/height 的區別:
flex-basis優先級高於width/height(當主軸為水平時,flex-basis替代width);- 若
flex-basis: 0%,則子元素的基準尺寸為 0,放大時忽略原寬度; - 若
flex-basis: auto,則子元素的基準尺寸為原寬度,放大時保留原寬度。
代碼演示(flex-basis: 0% vs auto):
.parent {
display: flex;
width: 500px;
gap: 10px;
padding: 20px;
background: #f5f5f5;
}
/\* flex-basis: 0%,忽略width,按比例放大 \*/
.item-0 {
width: 100px;
flex-basis: 0%;
flex-grow: 1;
background: #42b983;
}
/\* flex-basis: auto,保留width,再分配剩餘空間 \*/
.item-auto {
width: 100px;
flex-basis: auto;
flex-grow: 1;
background: #ff4757;
}
效果:
item-0:最終寬度 = 剩餘空間 / 2(忽略 100px);item-auto:最終寬度 = 100px + 剩餘空間 / 2(保留 100px)。
3.5 flex:flex-grow + flex-shrink + flex-basis 的簡寫
作用:簡化代碼,是子元素最常用的屬性,默認值0 1 auto。
常用快捷值及含義:
| 快捷值 | 等價於 | 效果 | 適用場景 |
|---|---|---|---|
| flex: 0 | flex: 0 1 0% | 不放大,可縮小,基準尺寸 0 | 固定尺寸元素(如圖標) |
| flex: 1 | flex: 1 1 0% | 放大,可縮小,基準尺寸 0 | 自適應元素(如中間欄) |
| flex: auto | flex: 1 1 auto | 放大,可縮小,基準尺寸 auto | 保留原尺寸的自適應元素 |
| flex: none | flex: 0 0 auto | 不放大,不縮小,基準尺寸 auto | 完全固定尺寸元素 |
核心區別:flex:1 vs flex:auto(面試高頻):
flex:1:flex-basis:0%,忽略子元素原寬度,按比例分配剩餘空間;flex:auto:flex-basis:auto,保留子元素原寬度,再分配剩餘空間。
代碼演示(區別對比):
.parent {
display: flex;
width: 500px;
gap: 10px;
padding: 20px;
background: #f5f5f5;
}
/\* flex:1 忽略width \*/
.item-1 {
width: 200px;
flex: 1;
background: #42b983;
}
/\* flex:auto 保留width \*/
.item-auto {
width: 200px;
flex: auto;
background: #ff4757;
}
效果:
item-1:最終寬度 = (500 - 10)/2 = 245px(忽略 200px);-
item-auto:最終寬度 = 200px + (500 - 200*2 -10)/2 = 245px?不,實際是:父元素總寬度 500,減去 gap10,剩餘 490;item-auto基準 200,item-1基準 0,總基準 200;剩餘空間 490-200=290;flex-grow都是 1,各分 145;所以item-auto最終 200+145=345,item-10+145=145。(注:實際計算需考慮 gap,這裏重點是 “flex:1 忽略 width,flex:auto 保留 width”)
3.6 align-self:單獨設置子元素的交叉軸對齊
作用:覆蓋父元素的align-items屬性,為單個子元素設置特殊的交叉軸對齊方式(默認 auto,即繼承父元素)。
取值:與align-items一致(flex-start、flex-end、center、baseline、stretch)。
代碼演示(特殊對齊的按鈕):
.form {
display: flex;
flex-direction: row;
align-items: center; /\* 父元素默認居中對齊 \*/
gap: 10px;
padding: 20px;
background: #f5f5f5;
}
.form-input {
flex-grow: 1;
padding: 8px;
border: 1px solid #ddd;
}
/\* 按鈕單獨向下對齊(覆蓋父元素的center) \*/
.form-btn {
padding: 8px 16px;
background: #42b983;
color: #fff;
border: none;
align-self: flex-end;
}
效果:輸入框垂直居中,按鈕靠底部對齊,滿足特殊佈局需求。
四、Flex 佈局避坑指南:解決 90% 常見錯誤
掌握屬性後,仍可能踩坑,這 3 個誤區最容易犯,一定要避開!
4.1 誤區 1:主軸方向設為 column 後,對齊屬性用反
錯誤場景:父元素flex-direction: column(主軸垂直),想讓子元素水平居中,卻用了justify-content: center(主軸對齊,此時控制垂直方向),導致沒效果。
正確做法:主軸垂直時,justify-content控制垂直方向,align-items控制水平方向。
/\* 錯誤:想水平居中,卻用了justify-content \*/
.parent {
display: flex;
flex-direction: column;
justify-content: center; /\* 此時控制垂直居中,不是水平 \*/
}
/\* 正確:水平居中用align-items \*/
.parent {
display: flex;
flex-direction: column;
align-items: center; /\* 水平居中 \*/
justify-content: center; /\* 垂直居中(可選) \*/
}
4.2 誤區 2:用 align-content 控制單行子元素
錯誤場景:子元素只有一行,卻用align-content: center想讓子元素垂直居中,結果沒效果。
原因:align-content僅對多行子元素生效,單行需用align-items。
正確做法:
/\* 錯誤:單行用align-content \*/
.parent {
display: flex;
align-content: center; /\* 單行無效 \*/
}
/\* 正確:單行用align-items \*/
.parent {
display: flex;
align-items: center; /\* 單行垂直居中 \*/
}
4.3 誤區 3:flex-shrink:0 導致子元素溢出
錯誤場景:子元素設置flex-shrink:0(不縮小),且寬度固定,當父元素寬度不足時,子元素溢出父元素。
解決方法:配合min-width: 0或overflow: hidden,讓子元素內容可壓縮或滾動。
/\* 錯誤:子元素溢出 \*/
.parent {
display: flex;
width: 200px; /\* 父元素寬度不足 \*/
}
.child {
width: 300px;
flex-shrink: 0; /\* 不縮小,導致溢出 \*/
}
/\* 正確:內容溢出時滾動 \*/
.child {
width: 300px;
flex-shrink: 0;
overflow-x: auto; /\* 橫向滾動 \*/
}
五、Flex 佈局實戰案例:從理論到應用
結合實際需求,用 Flex 實現 4 種常見佈局,鞏固所學知識。
5.1 案例 1:水平垂直居中(彈窗內容區)
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
/\* 父元素:水平垂直居中 \*/
display: flex;
justify-content: center;
align-items: center;
}
.modal-content {
width: 500px;
padding: 30px;
background: #fff;
border-radius: 8px;
}
5.2 案例 2:三欄佈局(後台管理系統)
.admin-layout {
display: flex;
width: 100%;
height: 100vh;
}
/\* 左側邊欄:固定寬度,不放大 \*/
.sidebar {
width: 240px;
flex-shrink: 0;
background: #2c3e50;
color: #fff;
}
/\* 中間內容區:自適應放大 \*/
.content {
flex-grow: 1;
padding: 20px;
background: #ecf0f1;
overflow-y: auto;
}
/\* 右側工具欄:固定寬度,不放大 \*/
.toolbar {
width: 200px;
flex-shrink: 0;
background: #fff;
padding: 20px;
}
5.3 案例 3:卡片網格(商品列表)
.product-list {
display: flex;
flex-flow: row wrap;
gap: 20px;
padding: 20px;
background: #f5f5f5;
/\* 讓卡片在父元素縮小時,自動調整數量 \*/
justify-content: flex-start;
align-content: flex-start;
}
.product-card {
width: calc((100% - 40px) / 3); /\* 一行3個,減去2個gap \*/
flex-shrink: 0; /\* 不縮小,保持寬度 \*/
height: 300px;
background: #fff;
border-radius: 8px;
overflow: hidden;
}
/\* 響應式:屏幕小於768px時,一行2個 \*/
@media (max-width: 768px) {
.product-card {
width: calc((100% - 20px) / 2);
}
}
5.4 案例 4:導航欄(兩端對齊 + 溢出滾動)
.nav {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
height: 60px;
padding: 0 20px;
background: #fff;
border-bottom: 1px solid #eee;
}
/\* 左側logo:固定寬度 \*/
.nav-logo {
width: 120px;
flex-shrink: 0;
}
/\* 中間菜單:溢出時滾動 \*/
.nav-menu {
display: flex;
gap: 20px;
margin: 0 20px;
overflow-x: auto;
/\* 隱藏滾動條,保留滾動功能 \*/
scrollbar-width: none;
-ms-overflow-style: none;
}
.nav-menu::-webkit-scrollbar {
display: none;
}
.nav-menu-item {
padding: 10px 0;
white-space: nowrap; /\* 不換行 \*/
}
/\* 右側用户區:固定寬度 \*/
.nav-user {
width: 100px;
flex-shrink: 0;
text-align: right;
}
六、Flex 屬性速查表(收藏備用)
父元素屬性速查表
| 屬性名 | 作用 | 取值 | 常用場景 |
|---|---|---|---|
| flex-direction | 決定主軸方向(子元素排列方向) | row/row-reverse/column/column-reverse | 水平 / 垂直佈局 |
| flex-wrap | 控制子元素是否換行 | nowrap/wrap/wrap-reverse | 卡片網格、列表 |
| flex-flow | 簡寫(direction+wrap) | ||
| justify-content | 主軸對齊方式 | flex-start/flex-end/center/space-between/space-around | 水平 / 垂直居中、兩端對齊 |
| align-items | 交叉軸單行對齊 | stretch/flex-start/flex-end/center/baseline | 垂直居中、等高佈局 |
| align-content | 交叉軸多行對齊 | stretch/flex-start/flex-end/center/space-between/space-around | 多行卡片對齊 |
子元素屬性速查表
| 屬性名 | 作用 | 取值 | 常用場景 |
|---|---|---|---|
| order | 改變排列順序 | (默認 0) | 置頂 / 置底元素 |
| flex-grow | 放大比例 | (默認 0) | 自適應元素(中間欄) |
| flex-shrink | 縮小比例 | (默認 1) | 固定尺寸元素(圖片) |
| flex-basis | 基準尺寸 | /auto(默認 auto) | 自定義基準尺寸 |
| flex | 簡寫(grow+shrink+basis) | 0/1/auto/none | 自適應、固定尺寸元素 |
| align-self | 單獨交叉軸對齊 | auto/flex-start/flex-end/center/baseline/stretch | 特殊對齊元素 |
結語:Flex 佈局的核心思想
Flex 佈局的本質是 “彈性”—— 通過主軸與交叉軸的靈活定義,實現 “按需分配空間” 和 “精準對齊”。掌握它的關鍵不是死記屬性,而是:
- 先確定主軸方向(
flex-direction); - 再用父元素屬性控制整體佈局;
- 最後用子元素屬性調整特殊需求。
多動手實現幾個實戰案例,遇到問題查速查表,很快就能熟練掌握。Flex 佈局是前端開發的 “瑞士軍刀”,用好它,能大幅提升佈局效率,告別 “浮動塌陷” 和 “定位混亂” 的煩惱!總而言之,一鍵點贊、評論、喜歡加收藏吧!這對我很重要!