目录
引子
最近接触 flex 布局的时候,碰到一些问题,于是借着这个机会,对 flex 相关的知识点进行整理。
简介
CSS 2.1 定义了 4 种布局模式,这些算法是根据盒子与它们的兄弟和祖先盒子的关系,来确定盒子自身大小和位置。分别有:
- block 布局,为文档布局设计
- inline 布局,为文本布局设计
- table 布局,为表格形式的 2D 数据布局设置
- positioned 布局,设计用于非常明确的定位,不用考虑文档中的其他元素
新引入的 flex 布局,跟 block 布局很类似,它缺少很多在 block 布局中,有关文本和文档相关的特性,例如浮动。相应的,它拥有了简单且强大的工具,用于来分配空间,并可以按照 web 应用程序和复杂网页经常需要的方式对齐内容。
目前处于候选推荐阶段,主流浏览器支持的情况很不错,详细见 Can I use flex。
相关概念和术语
一个元素设置 display
属性值为 flex
或 inline-flex
,就会变成一个 flex 容器(flex container),其直接子元素被称为 flex 项(flex items),它们布局使用 flex 布局模式。
在 CSS 中定义了一些跟物理方向和空间相对应的一些概念,这些概念为未来定义新的布局提供理论支持,在 flex 布局模式中对应物理方向和空间的概念如下图。
- main axis:主轴,flex 项的排列是按照主轴进行排列,主轴的方向取决于
flex-direction
属性,不一定是水平方向。 - main-start/main-end:flex 容器主轴上的开始/结束位置,flex 项的排列是从
main-start
开始,到main-end
结束。 - main-size:在主轴方向 flex 容器或者 flex 项的高度或宽度,它可能是元素的
width
或height
属性。类似的,它的min/max main size
属性取决于它的min-width/max-width
或者min-height/max-height
属性。 - cross axis:侧轴,跟主轴方向垂直的轴。
- cross-start/cross-end:flex 容器侧轴上的开始/结束位置,flex 项的排列是从
cross-start
开始,到cross-end
结束。 - cross-size:在侧轴方向 flex 容器或者 flex 项的高度或宽度,它可能是元素的
width
或height
属性。类似的,它的min/max cross size
属性取决于它的min-width/max-width
或者min-height/max-height
属性。
flex container
成为 flex 容器的方式是,设置 display
属性值为 flex | inline-flex
- flex:当一个块级元素放在流布局中,这个值会让这个元素生成一个 flex 容器盒子。
- inline-flex:当一个内联元素放在流布局中,这个值会让这个元素生成一个 flex 容器盒子。
flex 容器会为它的内容建立一个 flex 格式化上下文,它形成的包含块就像块级容器做的那样。flex 容器的外边距(margin)不会跟它内容的边距重合。overflow
属性适用于 flex 容器。flex 容器不是块级容器,并且有些适用于 block 布局的属性在 flex 布局中并不适用,特别是:
float
和clear
不会产生浮动或者清空 flex 项,并且不会让元素脱离文档流。vertical-align
对 flex 项没有作用。::first-line
和first-letter
伪元素不适用于 flex 容器,flex 容器不会为它们的祖先提供第一行格式化或第一个字母。
这是测试示例,移动端查看如下。
如果一个元素的 display
属性设置为 inline-flex
,在特定的环境下,它的的 display
属性会被计算为 flex
。
用于 flex 容器的相关属性有:
- flex-direction
- flex-wrap
- flex-flow
- justify-content
- align-items
- align-content
flex-direction
属性名:flex-direction
可取值:row | row-reverse | column | column-reverse
默认值:row
适用于:flex 容器
可继承:否
flex-direction
属性通过设置 flex 容器主轴的方向,来指定 flex 项在 flex 容器中的放置方式。
- row:flex 容器的主轴的方向与 writing mode 的 inline axis 相同。
main-start
和main-end
方向与 writing mode 的 inline-start 和 inline-end 方向一致。 - row-reverse:与
row
一样除了main-start
和main-end
的方向相反。 - column:flex 容器的主轴的方向与 writing mode 的 block axis 相同。
main-start
和main-end
方向与 writing mode 的 block-start 和 block-end 方向一致。 - column-reverse:与
column
一样除了main-start
和main-end
的方向相反。
这是测试示例,移动端查看如下。
flex-wrap
属性名:flex-wrap
可取值:nowrap | wrap | wrap-reverse
默认值:nowrap
适用于:flex 容器
可继承:否
flex-wrap
属性决定 flex 容器是单行还是多行,侧轴的方向决定了新行的插入方向。
- nowrap:flex 容器的子元素单行显示。
- wrap:flex 项在当前行显示不了时,会换行显示。
- wrap-reverse:flex 项在当前行显示不了时,会换行显示。
当值为非 wrap-reverse
时,cross-start
的方向与 当前 writing mode 的 inline-start 或 block-start 方向一致,当值为 wrap-reverse
时,cross-start
和 cross-end
方向相反。
这是测试示例,移动端查看如下。
flex-flow
flow-flow
是 flex-direction
和 flex-wrap
的缩写。
属性名:flex-flow
可取值:flex-direction
|| flex-wrap
适用于:flex 容器
可继承:否
justify-content
属性名:justify-content
可取值:flex-start | flex-end | center | space-between | space-around
默认值:flex-start
适用于:flex 容器
可继承:否
justify-content
属性沿着 flex 容器当前行的主轴对齐 flex 项。
- flex-start:flex 项向行的开始位置放置。行内第一个 flex 项的
main-start
外边距边界与行的main-start
的外边距边界齐平,每个后续的 flex 项与前一项齐平放置。 - flex-end:flex 项向行的结束位置放置。行内最后一个 flex 项的
main-end
外边距边界与行的main-end
的外边距边界齐平,每个前面的 flex 项与后续的项齐平放置。 - center:flex 项向行的中间位置放置。行内每个 flex 项齐平放置并与行的中心对齐,行的
main-start
边界与第一个 flex 项之间的空间,和行的main-end
边界与最后一个 flex 项之间的空间等量。 - space-between:flex 项在行内均匀分布。如果剩下的自由空间是负的,或者只有一个 flex 项在行内,这个值的作用与
flex-start
等同。除此之外,行内第一个 flex 项的main-start
外边距边界与行的main-start
的外边距边界对齐,行内最后一个 flex 项的main-end
外边距边界与行的main-end
的外边距边界对齐,剩下的 flex 项在行上均匀分布,任意两个相邻 flex 项的间距相同。 - space-around:flex 项在行内均匀分布,两端各有一半的空间。如果剩下的自由空间是负的,或者只有一个 flex 项在行内,这个值会被识别为
center
。除此之外,在行内任意两个相邻的 flex 项的间距相同,第一个和最后一个 flex 项与 flex 容器边界的间距是相邻 flex 项之间间距的一半。
这是测试示例,移动端查看如下。
align-items
属性名:align-items
可取值:flex-start | flex-end | center | baseline | stretch
默认值:stretch
适用于:flex 容器
可继承:否
align-items
设置所有 flex 容器的项的默认对齐方式,包括匿名的 flex 项。
- flex-start:flex 项的
cross-start
外边距边界与行的cross-start
边界对齐。 - flex-end:flex 项的
cross-end
外边距边界与行的cross-end
边界对齐。 - center:flex 项的外边距盒子在行的侧轴上中心。
- baseline:flex 项基于基线对齐,行内所有参与的 flex 项目都基于基线对齐,并且拥有基线与其自身的
cross-start
外边距边界最大距离的 flex 项,与行的cross-start
边界齐平。如果项目在必要的轴中没有基线,则从 flex 项的边框盒子合成基线。 - stretch:如果 flex 项的
cross size
属性计算为 auto,并且侧轴的的外边距都不是 auto,那么 flex 项会被拉伸。它使用的值是尽可能的让 项的外边距盒子的cross size
与行的大小一致的长度,仍然受到min-height/min-width/max-height/max-width
的约束。
这是测试示例,移动端查看如下。
align-content
属性名:align-content
可取值:flex-start | flex-end | center | space-between | space-around | stretch
默认值:stretch
适用于:多行 flex 容器
可继承:否
当在侧轴上有多余的空间时,align-content
属性让 flex 容器内的行对齐。注意,该属性对单行 flex 容器没有作用。
- flex-start:行向 flex 容器的开始位置放置。flex 容器内第一行的 cross-start 边界与flex 容器的 cross-start 边界齐平,后续的每行与前一行齐平。
- flex-end:行向 flex 容器的结束位置放置。flex 容器内最后一行的 cross-end 边界与flex 容器的 cross-end 边界齐平,每个前面的行与后续的行齐平放置。
- center:行向 flex 容器的中间位置放置。flex 容器内每一行都齐平放置并与 flex 容器的中心对齐,flex 容器内第一行与 flex 容器的 cross-start 内容边界的空间,和 flex 容器内最后一行与 flex 容器的 cross-end 内容边界的空间等量。
- space-between:行在 flex 容器内均匀分布。如果剩下的自由空间是负的,或者只有一行在 flex 容器内,这个值的作用与
flex-start
等同。除此之外,flex 容器内第一行的cross-start
边界与 flex 容器的cross-start
内容边界对齐,flex 容器内最后一行的main-end
边界与 flex 容器的main-end
的内容边界对齐,剩下的行在 flex 容器内均匀分布,任意相邻行的间距相同。 - space-round:行在 flex 容器内均匀分布,两端各有一半的空间。如果剩下的自由空间是负的,这个值的作用与
center
等同。除此之外,flex 容器内任意相邻的行的间距相同,第一行和最后一行与 flex 容器边界的间距是相邻行间距的一半。 - stretch:行会伸展占据剩余的空间。如果剩下的自由空间是负的,这个值的作用与
flex-start
等同。除此之外,剩余的空间会被所有的行平分。
这是测试示例,移动端查看如下。
flex item
flex 容器下每个在文档流里的后代都会成为一个 flex 项。每个连续的子文本都包含在匿名块容器 flex 项中。如果只包含空白符,就不会渲染,就好像文本节点拥有属性 display: none
。flex 项为它的内容建立一个独立的格式化上下文。然而,flex 项是 flex 级别盒子,不是 block 级别盒子,它们参与自己的 flex 格式化上下文,不是在 block 格式化上下文。
如果在 flex 容器内,在文档流的后代设置 display
为内联的值,其计算值与块级别值等效。也就是说这种情况下 flex 项的 display
属性值被锁定。详细见 CSS Display。
flex 容器内绝对定位,脱离文档流的后代不会参与 flex 布局。这样的 flex 容器的静态位置矩形(static-position rectangle )是它的内容盒子,这个静态位置矩形是用来决定绝对定位盒子偏移位置的容器。
相邻 flex 项的边距(margin)不会合并。flex 项的 margin
和 padding
为百分比时,跟块级盒子一样,会根据包含快的逻辑宽度计算。margin
的值为 auto
时,会在相应的维度,吸收额外的空间。它们可以用来对齐或者分开 flex 项。
用于 flex 项的相关属性有:
- flex
- order
- align-self
flex
属性名:flex
可取值:none | [ <‘flex-grow’> <‘flex-shrink’>? || <‘flex-basis’> ]
默认值:0 1 auto
适用于:flex 项
可继承:否
影响 flex 项长度有 flex 因子(增长和收缩)和 flex 基础。当一个盒子是 flex 项时,flex
属性决定了盒子的主要大小。如果一个盒子不是 flex 项,flex
属性将不会有作用。
flex 设置值为 none
时,相当于 0 0 auto
。
flex-grow
值为数字。当空间剩余时,这个属性决定了 flex 项相对于 flex 容器下其它 flex 项,会增长多少空间。当在 flex 简写中省略时,设置为 1 。
flex-shrink
值为数字。当空间不足时,这个属性决定了 flex 项相对于 flex 容器下其它 flex 项,会收缩多少空间。当在 flex 简写中省略时,设置为 1 。
flex-basis
flex-basis
定义了在分配多余空间前,flex 项的初始 main size。
- auto:使用该值时,将会取 main size 属性的值,如果 main size 属性的值也是 auto,则使用值
content
。 - content:基于 flex 项的内容大小自动生成。
- <‘width’>:除了上面两个值,
flex-basis
使用方式与width
和height
相同。
在 flex 简写中省略时,设置的值是 0 。
flex 常见值
- flex: initial:相当于
flex: 0 1 auto
。flex 项的大小基于width/height
属性。当有剩余空间时,不会分配剩余空间,但允许空间不足时缩小到最小尺寸。对齐的属性或者 auto 外边距可以用来让 flex 项沿主轴对齐。 - flex: auto:相当于
flex: 1 1 auto
。flex 项的大小基于width/height
属性。当有剩余空间时,会沿着主轴,尽可能的吸收剩余空间。如果所有项目都是flex: auto
,flex: initial
或flex: none
,则在项目大小调整后,任何剩余空间将均匀分配到具有属性flex: auto
的项。 - flex: none:相当于
flex: 0 0 auto
。flex 项的大小根据width/height
属性。盒子不会变得有弹性,跟取值initial
有点类似,但不允许 flex 项收缩,即使在溢出的情况下。 - flex:
<positive-number>
:相当于flex: <positive-number> 1 0
。flex 项接收 flex 容器中指定比例的可用空间。如果 flex 容器下所有 flex 项都使用这种模式,它们的大小将与指定的弹性系数成比例。
这是测试示例,移动端查看如下。
order
属性名:order
可取值:<integer>
默认值:0
适用于:flex 项
可继承:否
order
属性控制了 flex 项在 flex 容器里面显示的顺序。flex 容器放置内容,从最低编号开始按顺序向上。序号相同的组,会按照它们在源文档中出现的顺序放置。flex 容器内绝对定位的后代,会被当做拥有 order: 0
,这样做是为了决定它们相对于 flex 项的绘制顺序。
这是测试示例,移动端查看如下。
align-self
属性名:align-self
可取值:auto | flex-start | flex-end | center | baseline | stretch
默认值:auto
适用于:flex 项
可继承:否
align-self
作用跟 align-items
一样,但它适用于 flex 项,可以为单独的 flex 项设置对齐的方式,会覆盖 align-items
的效果。
如果 flex 项的侧轴任一外边距为 auto
,那么 align-self 无效。
align-self
比 align-items
多了一个可取值 auto
,使用该值时,对齐方式的控制权交给了父级盒子。
这是测试示例,移动端查看如下。