当你尝试让一个元素在页面中水平垂直居中,是否曾经写过这样的代码:设置绝对定位,然后手动计算top: 50%left: 50%,最后还要加上负的margin来修正偏移?当你在做导航栏时,是否为如何让几个链接均匀分布而头疼?这些问题在CSS Flexbox出现之前,确实需要各种"黑魔法"才能解决。

Flexbox(Flexible Box Layout,弹性盒布局)是CSS3引入的一种全新的布局模式,专门用于解决这些常见的布局难题。它让复杂的对齐、分布和响应式布局变得前所未有的简单。

什么是Flexbox

Flexbox是一种一维布局模型,它的核心思想是让容器能够改变其子元素的宽度、高度和顺序,以最佳方式填充可用空间。这种"弹性"特性使得Flexbox特别适合构建响应式界面。

2009年,W3C首次提出Flexbox规范。经过多次修订,最终在2017年成为W3C推荐标准。如今,所有现代浏览器都已完全支持Flexbox。

Flexbox的设计初衷是解决传统布局方式的痛点:

  • 垂直居中困难:在Flexbox之前,垂直居中需要各种技巧,如line-height、绝对定位配合transform
  • 等高列布局复杂:多列等高在传统布局中难以实现
  • 响应式布局繁琐:元素需要根据容器大小自动调整

核心概念:容器与项目

Flexbox的布局模型涉及两个核心角色:Flex容器(flex container)和Flex项目(flex item)。

当一个元素设置了display: flexdisplay: inline-flex,它就变成了一个Flex容器,而它的所有直接子元素自动成为Flex项目。

.container {
  display: flex;  /* 块级Flex容器 */
}

.inline-container {
  display: inline-flex;  /* 行内Flex容器 */
}

这是一个关键点:display: flex只影响直接子元素,不会影响更深层的后代元素。如果需要嵌套的Flex布局,需要在每一层都设置display: flex

主轴与交叉轴

理解Flexbox的关键在于理解主轴(main axis)和交叉轴(cross axis)的概念。

默认情况下:

  • 主轴是水平的,从左到右
  • 交叉轴是垂直的,从上到下

Flexbox主轴与交叉轴示意图

图片来源: CSS-Tricks - A Complete Guide to Flexbox

主轴的方向可以通过flex-direction属性改变。当主轴方向改变时,交叉轴也会相应改变——交叉轴始终与主轴垂直。

容器属性详解

flex-direction:决定主轴方向

flex-direction属性决定了Flex项目的排列方向。

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}
  • row(默认):主轴水平,从左到右
  • row-reverse:主轴水平,从右到左
  • column:主轴垂直,从上到下
  • column-reverse:主轴垂直,从下到上

flex-direction属性示意图

图片来源: CSS-Tricks - A Complete Guide to Flexbox

flex-wrap:是否换行

默认情况下,Flex项目会尝试排列在同一行。flex-wrap属性控制当空间不足时是否换行。

.container {
  flex-wrap: nowrap | wrap | wrap-reverse;
}
  • nowrap(默认):不换行,项目会被压缩
  • wrap:换行,第一行在上方
  • wrap-reverse:换行,第一行在下方

justify-content:主轴对齐

justify-content属性定义项目在主轴上的对齐方式,这是最常用的属性之一。

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}

justify-content属性示意图

图片来源: CSS-Tricks - A Complete Guide to Flexbox

  • flex-start(默认):起点对齐
  • flex-end:终点对齐
  • center:居中对齐
  • space-between:两端对齐,项目之间间隔相等
  • space-around:项目两侧间隔相等,但边缘间隔是中间的一半
  • space-evenly:所有间隔完全相等

align-items:交叉轴对齐

align-items属性定义项目在交叉轴上的对齐方式。

.container {
  align-items: stretch | flex-start | flex-end | center | baseline;
}

align-items属性示意图

图片来源: CSS-Tricks - A Complete Guide to Flexbox

  • stretch(默认):项目拉伸填满容器
  • flex-start:交叉轴起点对齐
  • flex-end:交叉轴终点对齐
  • center:交叉轴居中对齐
  • baseline:项目的文字基线对齐

gap:项目间距

gap属性用于设置项目之间的间距,这是较新但非常实用的属性。

.container {
  gap: 10px;  /* 统一间距 */
  gap: 10px 20px;  /* 行间距 列间距 */
}

gap只影响项目之间的间距,不会影响容器边缘的项目。

项目属性详解

flex-grow:放大比例

flex-grow定义项目的放大比例,默认为0(不放大)。

.item {
  flex-grow: <number>;  /* 默认 0 */
}

如果所有项目都设置flex-grow: 1,它们会等分剩余空间。如果一个项目设置flex-grow: 2,其他项目为1,则前者占据的剩余空间是其他项目的两倍。

flex-shrink:缩小比例

flex-shrink定义项目的缩小比例,默认为1(可缩小)。

.item {
  flex-shrink: <number>;  /* 默认 1 */
}

当空间不足时,项目会按比例缩小。设置flex-shrink: 0可以防止项目被压缩。

flex-basis:初始大小

flex-basis定义项目在分配多余空间之前的初始大小。

.item {
  flex-basis: <length> | auto;  /* 默认 auto */
}

auto表示使用项目本身的宽度或高度。可以设置为具体的长度值,如200px30%

flex简写属性

flexflex-growflex-shrinkflex-basis的简写,推荐使用简写形式。

.item {
  flex: none | <flex-grow> <flex-shrink>? <flex-basis>?;
}

常用的简写值:

  • flex: 0flex: 0 1 auto(默认值,不放大,可缩小)
  • flex: autoflex: 1 1 auto(可放大可缩小)
  • flex: noneflex: 0 0 auto(既不放大也不缩小)
  • flex: 1flex: 1 1 0%(可放大可缩小,初始大小为0)

align-self:单独对齐

align-self允许单个项目有与其他项目不同的对齐方式,可覆盖容器的align-items属性。

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

order:排列顺序

order属性可以改变项目的排列顺序,数值越小越靠前,默认为0。

.item {
  order: <integer>;  /* 默认 0 */
}

实战案例

水平垂直居中

这是Flexbox最经典的用法,只需三行代码:

.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

导航栏布局

Logo在左,导航链接在右:

.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

或者使用自动边距:

.nav {
  display: flex;
  align-items: center;
}

.logo {
  margin-right: auto;  /* 自动占据右侧所有空间 */
}

等宽卡片布局

三个卡片等宽排列,自动响应容器大小:

.card-container {
  display: flex;
  gap: 20px;
}

.card {
  flex: 1;  /* 等分空间 */
}

圣杯布局

经典的头部、主体、底部布局,中间主体自适应高度:

.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.main {
  flex: 1;  /* 占据剩余空间 */
}

常见陷阱

最小尺寸陷阱

Flex项目默认有min-width: auto,这会阻止项目缩小到内容最小宽度以下。如果发现项目怎么都无法缩小,尝试设置min-width: 0

.item {
  min-width: 0;  /* 允许项目完全收缩 */
}

宽度auto的问题

如果项目没有明确宽度(默认auto),justify-content可能不起作用,因为项目会自动撑满空间。确保给项目设置合适的尺寸或使用flex属性。

嵌套Flex的理解

每一层Flex容器只影响其直接子元素。如果需要在嵌套结构中使用Flex布局,需要在每一层都设置display: flex

小结

CSS Flexbox是现代Web布局的基石。掌握它,你就能轻松应对大多数布局需求。核心要点总结:

  1. display: flex创建Flex容器,直接子元素成为Flex项目
  2. 理解主轴和交叉轴的概念,这是所有属性的基础
  3. justify-content控制主轴对齐,align-items控制交叉轴对齐
  4. flex简写属性控制项目的伸缩行为
  5. 遇到奇怪的收缩行为时,检查min-width是否在起作用

Flexbox虽然概念较多,但实际使用中,最常用的也就是display: flexjustify-contentalign-itemsflex这几个属性。先掌握这些基础用法,再逐步探索更复杂的场景。


参考资料