CSS Flexible Box Layout

目录

引子

最近接触 flex 布局的时候,碰到一些问题,于是借着这个机会,对 flex 相关的知识点进行整理。

简介

CSS 2.1 定义了 4 种布局模式,这些算法是根据盒子与它们的兄弟和祖先盒子的关系,来确定盒子自身大小和位置。分别有:

  • block 布局,为文档布局设计
  • inline 布局,为文本布局设计
  • table 布局,为表格形式的 2D 数据布局设置
  • positioned 布局,设计用于非常明确的定位,不用考虑文档中的其他元素

新引入的 flex 布局,跟 block 布局很类似,它缺少很多在 block 布局中,有关文本和文档相关的特性,例如浮动。相应的,它拥有了简单且强大的工具,用于来分配空间,并可以按照 web 应用程序和复杂网页经常需要的方式对齐内容。

目前处于候选推荐阶段,主流浏览器支持的情况很不错,详细见 Can I use flex

相关概念和术语

一个元素设置 display 属性值为 flexinline-flex,就会变成一个 flex 容器(flex container),其直接子元素被称为 flex 项(flex items),它们布局使用 flex 布局模式。

在 CSS 中定义了一些跟物理方向和空间相对应的一些概念,这些概念为未来定义新的布局提供理论支持,在 flex 布局模式中对应物理方向和空间的概念如下图。

32-css-flex

  • main axis:主轴,flex 项的排列是按照主轴进行排列,主轴的方向取决于 flex-direction 属性,不一定是水平方向。
  • main-start/main-end:flex 容器主轴上的开始/结束位置,flex 项的排列是从 main-start 开始,到 main-end 结束。
  • main-size:在主轴方向 flex 容器或者 flex 项的高度或宽度,它可能是元素的 widthheight 属性。类似的,它的 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 项的高度或宽度,它可能是元素的 widthheight 属性。类似的,它的 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 布局中并不适用,特别是:

  • floatclear 不会产生浮动或者清空 flex 项,并且不会让元素脱离文档流。
  • vertical-align 对 flex 项没有作用。
  • ::first-linefirst-letter 伪元素不适用于 flex 容器,flex 容器不会为它们的祖先提供第一行格式化或第一个字母。

这是测试示例,移动端查看如下。

32-qrcode-flex-test

如果一个元素的 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 容器中的放置方式。

这是测试示例,移动端查看如下。

32-qrcode-flex-direction

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 modeinline-startblock-start 方向一致,当值为 wrap-reverse 时,cross-startcross-end 方向相反。

这是测试示例,移动端查看如下。

32-qrcode-flex-wrap

flex-flow

flow-flowflex-directionflex-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 项之间间距的一半。

32-justify-content

这是测试示例,移动端查看如下。

32-qrcode-justify-content

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 的约束。

32-align-items

这是测试示例,移动端查看如下。

32-qrcode-align-items

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 等同。除此之外,剩余的空间会被所有的行平分。

32-align-content

这是测试示例,移动端查看如下。

32-qrcode-align-content

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 项的 marginpadding 为百分比时,跟块级盒子一样,会根据包含快的逻辑宽度计算。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 使用方式与 widthheight 相同。

在 flex 简写中省略时,设置的值是 0 。

flex 常见值

  1. flex: initial:相当于 flex: 0 1 auto 。flex 项的大小基于 width/height 属性。当有剩余空间时,不会分配剩余空间,但允许空间不足时缩小到最小尺寸。对齐的属性或者 auto 外边距可以用来让 flex 项沿主轴对齐。
  2. flex: auto:相当于 flex: 1 1 auto 。flex 项的大小基于 width/height 属性。当有剩余空间时,会沿着主轴,尽可能的吸收剩余空间。如果所有项目都是 flex: autoflex: initialflex: none ,则在项目大小调整后,任何剩余空间将均匀分配到具有属性 flex: auto 的项。
  3. flex: none:相当于 flex: 0 0 auto 。flex 项的大小根据 width/height 属性。盒子不会变得有弹性,跟取值 initial 有点类似,但不允许 flex 项收缩,即使在溢出的情况下。
  4. flex: <positive-number>:相当于 flex: <positive-number> 1 0 。flex 项接收 flex 容器中指定比例的可用空间。如果 flex 容器下所有 flex 项都使用这种模式,它们的大小将与指定的弹性系数成比例。

这是测试示例,移动端查看如下。

32-qrcode-flex

order

属性名:order

可取值:<integer>

默认值:0

适用于:flex 项

可继承:否

order 属性控制了 flex 项在 flex 容器里面显示的顺序。flex 容器放置内容,从最低编号开始按顺序向上。序号相同的组,会按照它们在源文档中出现的顺序放置。flex 容器内绝对定位的后代,会被当做拥有 order: 0 ,这样做是为了决定它们相对于 flex 项的绘制顺序。

这是测试示例,移动端查看如下。

32-qrcode-order

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-selfalign-items 多了一个可取值 auto ,使用该值时,对齐方式的控制权交给了父级盒子。

这是测试示例,移动端查看如下。

32-qrcode-align-self

参考资料

posted @ 2020-03-13 18:50  XXHolic  阅读(177)  评论(0编辑  收藏  举报