一、两个轴
.box { display: flex; flex-direction: row; } /* 主轴水平,从左到右 */
.box { display: flex; flex-direction: column; } /* 主轴垂直,从上到下 */
- 主轴(main axis):由
flex-direction决定,justify-content作用于它。 - 交叉轴(cross axis):与主轴垂直,
align-items作用于它。
所以「水平居中 + 垂直居中」在 row 下是 justify-content: center + align-items: center;改成 column 后两者作用就互换了。记住「主轴看方向」比背属性表有用。
二、容器上的属性
| 属性 | 作用 |
|---|---|
justify-content | 主轴上的分布:flex-start / center / space-between / space-around / space-evenly |
align-items | 交叉轴上单行的对齐:stretch(默认,拉伸填满)/ center / flex-start / baseline |
align-content | 交叉轴上多行的分布(需 flex-wrap: wrap) |
flex-wrap | 是否换行,默认 nowrap(会压缩子元素) |
gap | 子元素间距,比给每个子元素加 margin 干净 |
space-between 与 space-around 的区别常被搞混:前者两端贴边、中间等距;后者每个元素左右各有等量空隙,所以两端是半个间距。
三、子元素上的 flex: 1 到底是什么
flex 是三个属性的缩写:
flex: 1; /* = flex-grow:1; flex-shrink:1; flex-basis:0% */
flex: auto; /* = 1 1 auto —— 按内容大小分配 */
flex: none; /* = 0 0 auto —— 不伸不缩 */
关键在 flex-basis: 0% 与 auto 的区别:
flex: 1→ 基准为 0,剩余空间平均分配,内容长的不会更宽。flex: auto→ 基准是内容宽度,剩余空间再按比例分,内容长的更宽。
所以做「三栏等宽」用 flex: 1,做「侧栏固定 + 主区自适应」用 flex: 1 配侧栏 flex: 0 0 240px。
四、五个常用套路
/* 1. 水平垂直居中 */
.center { display:flex; align-items:center; justify-content:center; min-height:100vh; }
/* 2. 侧栏固定 + 主区自适应 */
.layout { display:flex; gap:16px; }
.side { flex:0 0 240px; }
.main { flex:1; min-width:0; } /* min-width:0 防止内容撑破 */
/* 3. 等高列(默认行为) */
.row { display:flex; } /* 子元素默认 stretch,自动等高 */
/* 4. 两端对齐的导航栏 */
.nav { display:flex; justify-content:space-between; align-items:center; }
/* 5. 标签自动换行 */
.tags { display:flex; flex-wrap:wrap; gap:8px; }
五、三个高频坑
- 子元素被内容撑破:
flex:1的元素里有长英文或<pre>时,需要min-width:0(或overflow:hidden),否则它不会收缩。 align-items: stretch与固定高度冲突:给子元素设了height就不会拉伸,想让某个元素不拉伸用align-self。flex-wrap没开却想换行:默认nowrap会把子元素压扁,文字挤成竖排。
六、Flex 还是 Grid
一句话:一维排列用 Flex,二维网格用 Grid。导航栏、按钮组、卡片内部布局用 Flex;整页栅格、图片墙、表格式布局用 Grid(见 Grid 布局)。两者可以嵌套,不必二选一。
小结
主轴由 flex-direction 决定;justify-content 管主轴、align-items 管交叉轴;flex:1 是「基准 0 + 平均分」;被内容撑破时加 min-width:0。