A Complete Guide to Flexbox
背景知识:
弹性盒(Flexible Box)布局旨在提供一种更有效的方法来布置、对齐和分配容器中子元素之间的空间,即使它们的大小是未知的或动态的(因此使用了“flex”这个词)。
弹性布局的主要思想是给容器赋予改变其子元素的宽度/高度(和顺序)以最好地填充可用空间的能力(主要是为了适应各种显示设备和屏幕尺寸)。
最重要的是,弹性盒布局是无方向性的,而不像常规布局(块状布局是基于垂直方向的,行内布局是基于水平方向的)。虽然这些常规布局适用于页面,但是当开发大型或复杂应用程序时不够灵活(特别是当涉及到方向更改、调整大小、伸展、缩小等方面)。
基础知识和术语
由于弹性盒布局是一个完整的模块而不是单一属性,它的全部属性会涉及到很多方面。其中一些属性是针对容器(父元素,称为“flex container”)的,而另一些属性是针对子元素(称为“flex items”)的。
如果“常规”布局基于块和行内流方向,那么弹性布局则基于“弹性流方向”。下面的这张图解释了弹性布局的主要思想。
子元素项目将沿着主轴(从主起始点到主结束点)或交叉轴(从交叉起始点到交叉结束点)进行布局。
- 主轴 - 主轴(main axis)是flexbox 容器的一个属性,它是沿着其上面放置 flex 项目的主要方向。请注意,它不一定是水平的;它取决于 flex-direction 属性(见下文)。
- 主起始点 | 主结束点 - 弹性项目需要布局在容器的主起始点和主结束点之间。
- 主尺寸 - 弹性项目在主维度上的宽度或高度是其主尺寸。弹性项目的主尺寸是其是宽度”或“高度”属性中的一个,取决于主维度(也就是主轴的方向)。
- 交叉轴 - 垂直于主轴的轴称为交叉轴。它的方向取决于主轴方向。
- 交叉起始点 | 交叉结束点 - 在 Flexbox 中,交叉轴的起始位置是 Flex 容器中的左侧或顶部(取决于主轴方向),结束位置是 Flex 容器中的右侧或底部。Flexbox 中的元素按照主轴方向排列,当在交叉轴方向上需要分行时,Flexbox 会自动将元素分成多行,每行称为一个“Flex line”。这些 Flex lines 会依次填满 Flex 容器,从交叉轴的起始位置开始,一直填充到交叉轴的结束位置。
- 交叉尺寸 - 在弹性布局中,交叉尺寸(cross size)是指沿着交叉轴的尺寸,即与主轴垂直的方向的宽度或高度。一个项目的交叉尺寸由它在交叉轴上的宽度或高度决定,它的属性由它在交叉轴上的尺寸属性(width 或 height)来决定。如果一个项目在交叉轴上的尺寸属性是 width,那么它的交叉尺寸就是它的宽度,反之如果在交叉轴上的尺寸属性是 height,那么它的交叉尺寸就是它的高度。
Flexbox 属性
父元素(flex container)的属性
- display display 属性用于定义一个容器为 flex 容器。默认情况下,flex 容器是块级元素,但也可以设置为行内元素。在容器上设置 display:flex 后,它的所有直接子元素都可以参与 flex 布局。
.container { display: flex; /* 或 inline-flex */}
- flex-direction flex-direction用于指定 flex 容器的主轴方向。主轴方向定义了 flex 项目的排列方向。默认值是 row,表示主轴方向是水平方向,即从左到右。除此之外,还可以设置为 row-reverse、column、column-reverse 等。
.container { flex-direction: row | row-reverse | column | column-reverse;}
flex-direction: row
01
02
03
flex-direction: row-reverse
01
02
03
flex-direction: column
01
02
03
flex-direction: column-reverse
01
02
03
- flex-wrap flex-wrap 属性用于指定 flex 项目是否允许换行。默认情况下,所有项目会尽量放在一行上,当一行放不下时,它们会缩小以适应。但是,你可以通过设置 flex-wrap 属性,让项目可以换行。可选值包括 nowrap、wrap 和 wrap-reverse
- nowrap(默认):所有的flex子元素都将在一行上展示。
- wrap:flex子元素将会从上到下换行展示。
- wrap-reverse:flex子元素将会从下到上换行展示。
.container { flex-wrap: nowrap | wrap | wrap-reverse;}
flex-wrap: nowrap
flex-wrap: wrap
flex-wrap: wrap-reverse
-
flex-flow 属性,它是 flex-direction 和 flex-wrap 两个属性的缩写,用于同时设置它们的值。默认值是 row nowrap,即主轴方向是水平方向,不允许换行。
-
justify-content 属性 justify-content 定义了沿着主轴线的对齐方式。当所有的 flex 子项都无法缩小或已达到最大宽度时,它有助于分配额外的自由空间。当子项溢出行时,它还能在某种程度上控制它们的对齐方式。容器的justify-content属性可以设置以下取值:
- flex-start(默认值):子项向 flex-direction 的起始位置堆叠。
- flex-end:子项向 flex-direction 的结束位置堆叠。
- start:子项向书写方式的起始位置(the start of the writing-mode direction)堆叠。
- end:子项向书写方式的结束位置(he end of the writing-mode direction)堆叠。
- left:子项向容器的左边缘堆叠,除非这在 flex-direction 方向上不合理,那么它会表现得像 start 一样。
- right:子项向容器的右边缘堆叠,除非这在 flex-direction 方向上不合理,那么它会表现得像 end 一样。
- center:子项在行上居中对齐。
- space-between:子项在行上均匀分布,第一个子项在起始线上,最后一个子项在结束线上。
- space-around:子项在行上均匀分布,每个子项两侧的间隔相等。需要注意的是,虽然视觉上的空间不相等,但所有子项两侧的空间相等。第一个子项与容器边缘之间有一个单位的空间,但下一个子项之间的空间是两个单位,因为下一个子项有它自己的间隔。
- space-evenly:子项在行上均匀分布,任何两个子项之间(以及边缘之间的空间)的间距都相等。
.container { justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly | start | end | left | right ... + safe | unsafe;}
需要注意的是,这些取值的浏览器支持情况比较复杂。例如,某些版本的 Edge 不支持 space-between,Chrome 中也没有 start/end/left/right。MDN网站有详细的支持情况图表。最安全的取值是 flex-start、flex-end 和 center。
justify-content: flex-start
justify-content: flex-end
justify-content: center
justify-content: space-between
justify-content: space-around
justify-content: space-evenly
- align-items,这个属性决定了在交叉轴上,如何对齐子项。可以把它看做是与主轴垂直的justify-content属性。默认值为stretch,表示子项沿交叉轴拉伸以填充整个容器。
其他可能的值包括:
- stentch : 默认值,表示子项沿交叉轴拉伸以填充整个容器。
- flex-start / start / self-start:在交叉轴上的起始位置放置子项。可以理解为顶部对齐。
- flex-end / end / self-end:在交叉轴上的结束位置放置子项。可以理解为底部对齐。
- center:在交叉轴上居中放置伸缩项。垂直方向居中对齐。
- baseline:按子项的baseline对齐。
.container { align-items: stretch | flex-start | flex-end | center | baseline | first baseline | last baseline | start | end | self-start | self-end + ... safe | unsafe;}
align-items: stretch
align-items: flex-start
align-items: flex-end
align-items: center
align-items: baseline
- align-content align-content是用于控制flex容器内多行子元素在交叉轴上的对齐方式,类似于justify-content控制主轴上的对齐方式。它可以让一组子元素聚集在顶部或底部,或者拉伸以填充空间,或者在行之间留有间距。
需要注意的是,该属性仅在多行flex容器中生效,即flex-wrap属性设置为wrap或wrap-reverse。单行flex容器(即flex-wrap属性设置为默认值no-wrap的情况)不会受到align-content的影响。
align-content属性的取值有:
- normal(默认值):项目将按照默认位置排列,就好像没有设置该属性一样。
- flex-start / start:所有子元素将排列在容器的开始位置。
- flex-end / end:所有子元素将排列在容器的结束位置。flex-end更支持flex-direction,而end则支持writing-mode的方向。
- center:所有子元素在容器中垂直居中对齐。
- space-between:所有子元素平均分布;第一行在容器的开始位置,最后一行在容器的结束位置。
- space-around:所有子元素均匀分布,每行周围有相同的空间。
- space-evenly:所有子元素均匀分布,每行之间有相等的空间。
- stretch:每一行子元素都将拉伸以占用交叉轴方向的剩余空间。
align-content: normal
align-content: flex-start
align-content: flex-end
align-content: center
align-content: space-between
align-content: space-evenly
align-content: space-around
align-content: stretch
- gap, row-gap, column-gap 这几个gap相关的属性,用于控制flex items之间的间距。它仅适用于非外边缘的子元素之间的间距。 这个属性可以通过指定一个或两个值来设置,第一个值表示行间距,第二个值表示列间距,如果只指定一个值,则它将应用于行和列的间距。 该属性的行间距和列间距也可以分别使用row-gap和column-gap属性单独设置。
此外,该属性被认为是一个最小的间隙,如果因为某些原因(例如justify-content: space-between)间隔变大,则间隔将仅在该空间变小时生效。 此属性不仅适用于flexbox,还适用于grid and multi-column 布局。
.container { display: flex; ... gap: 10px; gap: 10px 20px; /* row-gap column gap */ row-gap: 10px; column-gap: 20px;}
子元素(flex items)的属性
- order,默认情况下,Flex 容器中的子元素是按照它们在源代码中出现的顺序进行布局的。但是,可以使用 order 属性来控制它们在容器中出现的顺序。通过在子元素上设置 order 属性,可以将某个子元素移动到其子元素的前面或后面。
在下面的示例中,.item 类选择器表示将 order 属性应用于具有 .item 类的 Flex 子元素。order 属性的默认值是 0,但是可以将其设置为任何数字值,以使项目出现在其他项目之前或之后。值越大,项目在 Flex 容器中出现的位置就越靠后。
此外,如果两个或多个项目具有相同的 order 值,则它们将按照它们在源代码中的出现顺序进行布局。也就是说,如果两个项目的 order 属性都设置为 1,则它们仍然会按照它们在源代码中的顺序进行布局。
- flex-grow,它定义了flex 子元素在需要时如何进行扩展。这个属性接受一个无单位的值,该值作为一个比例。它决定了子元素应该占据flex容器可用空间的多少。
如果所有子元素的flex-grow属性都设置为1,那么容器中剩余的空间将被平均分配给所有子元素。如果其中一个子元素的值为2,那么这个子元素占用的空间将是其他子元素中任何一个的两倍。
.item { flex-grow: 1; /* default 0 */}
- flex-basis 属性定义了元素在剩余空间分配之前的默认大小。它可以是一个长度值(例如 20%、5rem 等)。
.item { flex-basis: | auto; /* default auto */}