CSS Flexbox 布局指南

Avatar of Chris Coyier
Chris Coyier

我们关于 CSS flexbox 布局的综合指南。本完整指南解释了 flexbox 的所有内容,重点介绍父元素(flex 容器)和子元素(flex 项目)所有可能的属性。它还包括历史记录、演示、模式和浏览器支持图表。

由 DigitalOcean 提供

DigitalOcean 提供您在任何阶段成长所需的云计算服务。立即使用 200 美元的免费积分开始!

获取海报!

经常参考本指南?这里有一张您可以打印的高分辨率图像!


背景

Flexbox 布局(弹性盒)模块(截至 2017 年 10 月的 W3C 候选推荐)旨在提供一种更有效的方法来布局、对齐和分配容器中项目的空间,即使它们的大小未知和/或动态(因此是“弹性”)。

弹性布局背后的主要思想是赋予容器改变其项目宽度/高度(和顺序)的能力,以最佳方式填充可用空间(主要用于适应各种显示设备和屏幕尺寸)。弹性容器会扩展项目以填充可用空闲空间,或收缩项目以防止溢出。

最重要的是,弹性盒布局与方向无关,而常规布局(垂直为基础的块布局和水平为基础的行内布局)则与方向有关。虽然这些布局对页面来说效果很好,但它们缺乏灵活性(没有双关语意)来支持大型或复杂应用程序(尤其是在方向变化、调整大小、拉伸、收缩等方面)。

**注意:** 弹性盒布局最适合应用程序的组件和小规模布局,而网格布局则适用于更大规模的布局。

基础和术语

由于 flexbox 是一个完整的模块,而不是单个属性,因此它涉及很多内容,包括其所有属性。其中一些属性是为容器(父元素,称为“flex 容器”)设置的,而其他属性是为子元素(称为“flex 项目”)设置的。

如果“常规”布局基于块流和行内流方向,则 flex 布局基于“flex 流方向”。请查看规范中的这张图,了解弹性布局背后的主要思想。

A diagram explaining flexbox terminology. The size across the main axis of flexbox is called the main size, the other direction is the cross size. Those sizes have a main start, main end, cross start, and cross end.

项目将按照主轴(从main-startmain-end)或交叉轴(从cross-startcross-end)进行排列。

  • **主轴** – 弹性容器的主轴是弹性项目沿其排列的主要轴。请注意,它不一定是水平的;它取决于flex-direction属性(见下文)。
  • **main-start | main-end** – 弹性项目从 main-start 开始,一直到 main-end 在容器中放置。
  • **主尺寸** – 弹性项目的宽度或高度(无论哪个在主维度上)就是该项目的“主尺寸”。弹性项目的“主尺寸”属性是“width”或“height”属性中的任何一个,无论哪个在主维度上。
  • **交叉轴** – 垂直于主轴的轴称为交叉轴。它的方向取决于主轴的方向。
  • **cross-start | cross-end** – 弹性线用项目填充,并从弹性容器的 cross-start 侧开始,一直到 cross-end 侧放置在容器中。
  • **交叉尺寸** – 弹性项目的宽度或高度(无论哪个在交叉维度上)就是该项目的“交叉尺寸”。“交叉尺寸”属性是“width”或“height”属性中的任何一个,无论哪个在交叉维度上。

Flexbox 属性

父元素的属性
(flex 容器)

display

这定义了一个弹性容器;根据给定值,它可以是内联或块级元素。它为其所有直接子元素启用弹性上下文。

.container {
  display: flex; /* or inline-flex */
}

请注意,CSS 列对弹性容器没有影响。

flex-direction

the four possible values of flex-direction being shown: top to bottom, bottom to top, right to left, and left to right


这将建立主轴,从而定义弹性项目在弹性容器中的放置方向。弹性盒子是一种单方向布局概念(除了可选的换行)。可以将弹性项目视为主要水平排列成行或垂直排列成列。

.container {
  flex-direction: row | row-reverse | column | column-reverse;
}
  • row(默认):在 ltr 中从左到右;在 rtl 中从右到左
  • row-reverse:在 ltr 中从右到左;在 rtl 中从左到右
  • column:与 row 相同,但从上到下
  • column-reverse:与 row-reverse 相同,但从下到上

flex-wrap

two rows of boxes, the first wrapping down onto the second

默认情况下,弹性项目都会尝试适应一行。可以使用此属性更改此设置,并允许项目根据需要换行。

.container {
  flex-wrap: nowrap | wrap | wrap-reverse;
}
  • nowrap(默认):所有弹性项目都将在一行上
  • wrap:弹性项目将换行到多行,从上到下。
  • wrap-reverse:弹性项目将换行到多行,从下到上。

这里有一些关于 flex-wrap视觉演示

flex-flow

这是 flex-directionflex-wrap 属性的简写,它们一起定义了弹性容器的主轴和交叉轴。默认值为 row nowrap

.container {
  flex-flow: column wrap;
}

justify-content

flex items within a flex container demonstrating the different spacing options


这定义了沿主轴的对齐方式。它有助于分配当一行上的所有弹性项目都是不可伸缩的,或者可伸缩但已达到其最大大小时,剩余的额外空闲空间。它还在弹性项目溢出该行时对项目的对齐方式施加一些控制。

.container {
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly | start | end | left | right ... + safe | unsafe;
}
  • flex-start(默认):项目将被压缩到弹性方向的开头。
  • flex-end:项目将被压缩到弹性方向的末尾。
  • start:项目将被压缩到 writing-mode 方向的开头。
  • end:项目将被压缩到 writing-mode 方向的末尾。
  • left:项目将被压缩到容器的左侧边缘,除非这与 flex-direction 不一致,在这种情况下,它将表现得像 start
  • right:项目将被压缩到容器的右侧边缘,除非这与 flex-direction 不一致,在这种情况下,它将表现得像 end
  • center:项目将沿该行居中
  • space-between:项目在该行中均匀分布;第一个项目在起始行,最后一个项目在末尾行
  • space-around:项目在该行中均匀分布,并在它们周围留有相等的空间。请注意,视觉上空间并不相等,因为所有项目都两侧留有相等的空间。第一个项目将与容器边缘相隔一个单位空间,但在下一个项目之间将留有 2 个单位空间,因为下一个项目有其自己的间距适用。
  • space-evenly:项目将分布以便任何两个项目之间的间距(以及到边缘的间距)相等。

请注意,这些值的浏览器支持存在细微差别。例如,某些版本的 Edge 从未支持 space-between,并且 start/end/left/right 尚未出现在 Chrome 中。MDN 提供了详细的图表。最安全的价值观是 flex-startflex-endcenter

还可以将这两个附加关键字与这些值配对:safeunsafe。使用 safe 可确保无论如何进行此类定位,都不会将元素推到屏幕外(例如,推到顶部)以至于内容无法滚动(称为“数据丢失”)。

align-items

demonstration of differnet alignment options, like all boxes stuck to the top of a flex parent, the bottom, stretched out, or along a baseline


这定义了弹性项目在当前行上沿**交叉轴**布局的默认行为。可以将其视为 justify-content 的交叉轴版本(垂直于主轴)。

.container {
  align-items: stretch | flex-start | flex-end | center | baseline | first baseline | last baseline | start | end | self-start | self-end + ... safe | unsafe;
}
  • stretch(默认):伸展以填充容器(仍然尊重最小宽度/最大宽度)
  • flex-start / start / self-start:项目将放置在交叉轴的开头。它们之间的区别很细微,在于是否尊重 flex-direction 规则或 writing-mode 规则。
  • flex-end / end / self-end:项目将放置在交叉轴的末尾。再次,区别很细微,在于是否尊重 flex-direction 规则或 writing-mode 规则。
  • center:项目将交叉轴居中
  • baseline:项目将对齐,使其基线对齐

safeunsafe 修饰符关键字可以与所有其他关键字一起使用(尽管请注意 浏览器支持),并且有助于防止对齐元素以至于内容变得无法访问。

align-content

examples of the align-content property where a group of items cluster at the top or bottom, or stretch out to fill the space, or have spacing.


此属性用于在交叉轴上有额外空间时对齐 flex 容器的线条,类似于 `justify-content` 如何在主轴上对齐单个项目。

注意:此属性仅对多行弹性容器生效,其中 `flex-wrap` 设置为 `wrap` 或 `wrap-reverse`。单行弹性容器(即 `flex-wrap` 设置为其默认值 `no-wrap`)不会反映 `align-content`。

.container {
  align-content: flex-start | flex-end | center | space-between | space-around | space-evenly | stretch | start | end | baseline | first baseline | last baseline + ... safe | unsafe;
}
  • normal(默认):项目按默认位置排列,就像没有设置任何值一样。
  • flex-start / start:项目排列在容器的开头。更受支持的 `flex-start` 遵循 `flex-direction`,而 `start` 遵循 `writing-mode` 方向。
  • flex-end / end:项目排列在容器的末尾。更受支持的 `flex-end` 遵循 `flex-direction`,而 `end` 遵循 `writing-mode` 方向。
  • center:项目在容器中居中。
  • space-between:项目均匀分布;第一行在容器的开头,而最后一行在末尾。
  • space-around:项目均匀分布,每行周围有相等的间隔。
  • space-evenly:项目均匀分布,它们周围有相等的间隔。
  • stretch:线条拉伸以占据剩余的空间。

safeunsafe 修饰符关键字可以与所有其他关键字一起使用(尽管请注意 浏览器支持),并且有助于防止对齐元素以至于内容变得无法访问。

gap, row-gap, column-gap

`gap` 属性明确控制弹性项目之间的间距。它仅在项目之间应用间距,而不是在外部边缘。

.container {
  display: flex;
  ...
  gap: 10px;
  gap: 10px 20px; /* row-gap column gap */
  row-gap: 10px;
  column-gap: 20px;
}

可以将其行为视为最小间距,就像间距更大(例如,由于 `justify-content: space-between;`)一样,则间距仅在该间距最终变小的情况下才生效。

它不只适用于 flexbox,`gap` 也适用于网格和多列布局。

子元素的属性
(弹性项目)

order

Diagram showing flexbox order. A container with the items being 1 1 1 2 3, -1 1 2 5, and 2 2 99.


默认情况下,弹性项目按源代码顺序排列。但是,`order` 属性控制它们在弹性容器中显示的顺序。

.item {
  order: 5; /* default is 0 */
}

具有相同 `order` 的项目将恢复为源代码顺序。

flex-grow

two rows of items, the first has all equally-sized items with equal flex-grow numbers, the second with the center item at twice the width because its value is 2 instead of 1.


此属性定义弹性项目在必要时增长的能力。它接受一个无单位的值,用作比例。它指示项目应占用弹性容器内可用空间的多少比例。

如果所有项目的 `flex-grow` 都设置为 `1`,容器内的剩余空间将平均分配给所有子元素。如果一个子元素的值为 `2`,则该子元素将占用其他子元素的 2 倍空间(或者至少会尝试)。

.item {
  flex-grow: 4; /* default 0 */
}

负数是无效的。

flex-shrink

此属性定义弹性项目在必要时收缩的能力。

.item {
  flex-shrink: 3; /* default 1 */
}

负数是无效的。

flex-basis

此属性定义分配剩余空间之前的元素的默认大小。它可以是长度(例如,20%、5rem 等)或关键字。`auto` 关键字表示“查看我的宽度或高度属性”(在 `main-size` 关键字被弃用之前,它暂时使用 `main-size` 关键字来执行此操作)。`content` 关键字表示“根据项目内容的大小来确定大小” - 此关键字尚未得到很好的支持,因此难以测试,更难知道其同类 `max-content`、`min-content` 和 `fit-content` 的作用。

.item {
  flex-basis:  | auto; /* default auto */
}

如果设置为 `0`,则不会考虑内容周围的额外空间。如果设置为 `auto`,则额外空间将根据其 `flex-grow` 值进行分配。查看此图形。

flex

这是 `flex-grow`、`flex-shrink` 和 `flex-basis` 的简写形式。第二个和第三个参数(`flex-shrink` 和 `flex-basis`)是可选的。默认值为 `0 1 auto`,但如果使用单个数字值进行设置,例如 `flex: 5;`,则会将 `flex-basis` 更改为 0%,因此它类似于设置 `flex-grow: 5; flex-shrink: 1; flex-basis: 0%;`。

.item {
  flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}

建议您使用此简写属性,而不是设置各个属性。简写会智能地设置其他值。

align-self

One item with a align-self value is positioned along the bottom of a flex parent instead of the top where all the rest of the items are.


这允许覆盖单个弹性项目默认的对齐方式(或由align-items指定的对齐方式)。

请参阅align-items说明以了解可用值。

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

请注意,floatclearvertical-align对弹性项目没有影响。

Flexbox 前缀

Flexbox 需要一些供应商前缀才能尽可能支持最多的浏览器。它不仅仅包括在属性前面加上供应商前缀,而且实际上有完全不同的属性和值名称。这是因为 Flexbox 规范随着时间的推移而发生变化,形成了“旧”、“过渡”和“新”版本。

也许最好的方法是用新的(也是最终的)语法编写,然后将您的 CSS 通过Autoprefixer运行,它可以很好地处理回退。

或者,这里有一个 Sass @mixin 来帮助处理一些前缀,这也让您了解需要做什么样的操作

@mixin flexbox() {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
}

@mixin flex($values) {
  -webkit-box-flex: $values;
  -moz-box-flex:  $values;
  -webkit-flex:  $values;
  -ms-flex:  $values;
  flex:  $values;
}

@mixin order($val) {
  -webkit-box-ordinal-group: $val;  
  -moz-box-ordinal-group: $val;     
  -ms-flex-order: $val;     
  -webkit-order: $val;  
  order: $val;
}

.wrapper {
  @include flexbox();
}

.item {
  @include flex(1 200px);
  @include order(2);
}

示例

让我们从一个非常非常简单的示例开始,解决一个几乎每天都会遇到的问题:完美居中。如果您使用 Flexbox,再简单不过了。

.parent {
  display: flex;
  height: 300px; /* Or whatever */
}

.child {
  width: 100px;  /* Or whatever */
  height: 100px; /* Or whatever */
  margin: auto;  /* Magic! */
}

这依赖于在 Flex 容器中设置为auto的边距会吸收额外的空间。因此,设置auto的边距将使项目在两个轴上完美居中。

现在让我们使用更多属性。考虑一个包含 6 个项目的列表,所有项目都具有固定尺寸,但可以自动调整大小。我们希望它们均匀地分布在水平轴上,这样当我们调整浏览器大小时,所有内容都能很好地缩放,并且无需媒体查询。

.flex-container {
  /* We first create a flex layout context */
  display: flex;

  /* Then we define the flow direction 
     and if we allow the items to wrap 
   * Remember this is the same as:
   * flex-direction: row;
   * flex-wrap: wrap;
   */
  flex-flow: row wrap;

  /* Then we define how is distributed the remaining space */
  justify-content: space-around;
}

完成了。其他所有内容只是样式问题。下面是一个包含此示例的笔。请务必访问 CodePen 并尝试调整您的窗口大小,看看会发生什么。

让我们尝试其他一些东西。想象一下,我们在网站最顶部有一个右对齐的导航元素,但我们希望它在中等大小的屏幕上居中,在小型设备上单列显示。很容易。

/* Large */
.navigation {
  display: flex;
  flex-flow: row wrap;
  /* This aligns items to the end line on main-axis */
  justify-content: flex-end;
}

/* Medium screens */
@media all and (max-width: 800px) {
  .navigation {
    /* When on medium sized screens, we center it by evenly distributing empty space around items */
    justify-content: space-around;
  }
}

/* Small screens */
@media all and (max-width: 500px) {
  .navigation {
    /* On small screens, we are no longer using row direction but column */
    flex-direction: column;
  }
}

让我们尝试通过玩转弹性项目灵活性来实现更好的效果!一个移动优先的 3 列布局,带有全宽的页眉和页脚。并且独立于源顺序。

.wrapper {
  display: flex;
  flex-flow: row wrap;
}

/* We tell all items to be 100% width, via flex-basis */
.wrapper > * {
  flex: 1 100%;
}

/* We rely on source order for mobile-first approach
 * in this case:
 * 1. header
 * 2. article
 * 3. aside 1
 * 4. aside 2
 * 5. footer
 */

/* Medium screens */
@media all and (min-width: 600px) {
  /* We tell both sidebars to share a row */
  .aside { flex: 1 auto; }
}

/* Large screens */
@media all and (min-width: 800px) {
  /* We invert order of first sidebar and main
   * And tell the main element to take twice as much width as the other two sidebars 
   */
  .main { flex: 3 0px; }
  .aside-1 { order: 1; }
  .main    { order: 2; }
  .aside-2 { order: 3; }
  .footer  { order: 4; }
}

Flexbox 技巧!

浏览器支持

此浏览器支持数据来自 Caniuse,其中包含更多详细信息。数字表示浏览器从该版本开始支持该功能。

桌面

ChromeFirefoxIEEdgeSafari
21*2811126.1*

移动设备/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari
1271274.47.0-7.1*

Bug

Flexbox 当然也存在一些 Bug。我见过的最全面的 Bug 集合是 Philip Walton 和 Greg Whitworth 的 Flexbugs。这是一个开源的 Bug 追踪平台,所以我建议直接链接到它。

相关属性

更多信息

更多资源