css

Flexbox

CSS 2.1 定义了四种布局模式 ― 由一个盒与其兄弟、祖先盒的关系决定其尺寸与位置的算法:

  • 块布局: 为了呈现文档而设计出来的布局模式
  • 行内布局: 为了呈现文本而设计出来的布局模式
  • 表格布局: 为了用格子呈现 2D 数据而设计出来的布局模式
  • 定位布局: 为了非常直接地定位元素而设计出来的布局模式,定位元素基本与其他元素毫无关系

本文介绍新的布局模式:伸缩布局,是为了呈现复杂的应用与页面而设计出来的。Flexbox布局(Flexible Box)模块旨在提供一个更加有效的方式来制定、调整和分布一个容器里的项目布局,即使他们的大小是未知或者是动态的。(这里我们称为Flex)

Flex布局主要思想是让容器有能力让其子项目能够改变其宽度、高度(甚至顺序),以最佳方式填充可用空间(主要是为了适应所有类型的显示设备和屏幕大小)。Flex容器会使子项目(伸缩项目)扩展来填满可用空间,或缩小他们以防止溢出容器。。这玩意天生就是说布局用的,他不是一个 CSS 属性,是咦整个模块,包括一大组属性。

伸缩布局盒模型和术语

一个设有display:flexdisplay:inline-flex的元素是一个伸缩容器,伸缩容器的子元素被称为伸缩项目,这些子元素使用伸缩布局模型来排版。 与布局计算偏向使用书写模式方向的块布局与行内布局不同,伸缩布局偏向使用伸缩流的方向。为了让描述伸缩布局变得更容易,本章节定义一系列相对于伸缩流的术语。flex-flow的值决定了这些术语如何对应到物理方向(上/右/下/左)、物理轴(垂直/水平)、物理大小(宽度/高度)。

flex-flow

这个图对于理解 FLexbox 十分重要,你可以多看她两眼。在这里,外面是一个伸缩容器,里面的1和2 是两个伸缩项目。

主轴、主轴方向

用户代理沿着一个伸缩容器的主轴配置伸缩项目,主轴是主轴方向的延伸。

主轴起点、主轴终点

伸缩项目的配置从容器的主轴起点边开始,往主轴终点边结束。

主轴长度、主轴长度属性

伸缩项目的在主轴方向的宽度或高度就是项目的主轴长度,伸缩项目的主轴长度属性是widthheight属性,由哪一个对着主轴方向决定。

侧轴、侧轴方向

与主轴垂直的轴称作侧轴,是侧轴方向的延伸。

侧轴起点、侧轴终点

填满项目的伸缩行的配置从容器的侧轴起点边开始,往侧轴终点边结束。

侧轴长度、侧轴长度属性

伸缩项目的在侧轴方向的宽度或高度就是项目的侧轴长度,伸缩项目的侧轴长度属性是widthheight属性,由哪一个对着侧轴方向决定。

伸缩容器

设置一个容器的display属性值为flex或者inline-flex,那么这个容器就是一个伸缩容器,伸缩容器会为其内容建立新的伸缩格式化上下文(flex formatting context)。伸缩容器不是块容器,因此有些设计用来控制块布局的属性,在伸缩布局中不适用。特别是:column,float,clear,vertial-align。

伸缩项目

伸缩容器的子节点都是伸缩项目。

基本属性

FLexbox 的基本属性涉及到以下几个方面,按所属元素来说,分为伸缩容器属性和伸缩项目属性,这个需要区分开来。按照功能划分,分为排序与方向,伸缩性和对齐方式三大内,排序与方向包括flex-directionflex-wraporder,伸缩性包含一个缩写属性flex,对齐方式内包括justify-contentalign-itemalign-contentalign-self,下面将详细描述。

排序与方向

伸缩容器的内容可以用任何方向与任何顺序进行布局,我们可以轻松地达到之前需要复杂、不牢靠的floatclear属性才可以实现的效果。这个功能透过flex-directionflex-wraporder属性呈现。

伸缩流的方向 - flex-dirction

flex-direction属性可以用来设定伸缩容器的主轴的方向,这也决定了用户代理配置伸缩项目的方向。

  • row:伸缩容器的主轴与当前书写模式的行内轴(文字布局的主要方向)同向。主轴起点与主轴终点方向分别等同于当前书写模式的始与结方向。
  • row-reverse:除了主轴起点与主轴终点方向交换以外同row
  • column:伸缩容器的主轴与当前书写模式的块轴(块布局的主要方向)同向。主轴起点与主轴终点方向分别等同于当前书写模式的前与后方向。
  • column-reverse:除了主轴起点与主轴终点方向交换以外同column

伸缩行换行 - flex-wrap

flex-wrap属性控制伸缩容器是单行还是多行,也决定了侧轴方向 ― 新的一行的堆放方向。

  • nowrap: 伸缩容器为单行。侧轴起点方向等同于当前书写模式的起点或前/头在侧轴的那一边,而侧轴终点方向是侧轴起点的相反方向。
  • wrap:伸缩容器为多行。侧轴起点方向等同于当前书写模式的起点或前/头在侧轴的那一边,而侧轴终点方向是侧轴起点的相反方向。
  • wrap-reverse:除了侧轴起点与侧轴终点方向交换以外同wrap

伸缩方向与换行 - flex-flow

flex-flow属性是同时设定flex-directionflex-wrap属性的缩写,两个属性决定了伸缩容器的主轴与侧轴。

显示顺序 - order

默认状态下,用户代理会用伸缩项目出现在源文档的次序配置这些伸缩项目。order属性可以用来改变这个顺序。

伸缩性

之所以说 Flexbox 天生就是用来布局的是因为他有两个决定性的特性

  • 控制伸缩项目的排列方向和顺序,这个上面已经说的比较清楚了
  • 让伸缩项目可伸缩,也就是让伸缩项目的宽度或高度自动填充剩余的空间,下面详细说说伸缩性

这可以以flex属性完成。一个伸缩容器会等比地按照各伸缩项目的扩展比率分配剩余空间,也会按照伸缩比率缩小各项目以避免溢出。

flex属性可以用来指定可伸缩长度的部件:扩展比率、伸缩比率,以及伸缩基准值。当一个元素是伸缩项目时,flex属性将代替主轴长度属性决定元素的主轴长度。若元素不是伸缩项目,则flex属性没有效果。

扩展比率 - flex-grow

定义伸缩项目的扩展能力,也就是剩余空间是正值的时候此伸缩项目相对于伸缩容器里其他伸缩项目能分配到空间比例。通俗的说就是伸缩项目占剩余共空间的几成,如果所有伸缩项目的flex-grow: 1;,那么每个伸缩项目将设置为一个大小相等的剩余空间。如果你给其中一个伸缩项目设置了flex-grow: 2;,那么这个伸缩项目所占的剩余空间是其他伸缩项目所占剩余空间的两倍。

伸缩比率 - flex-shrink

定义伸缩项目伸缩的能力,也就是剩余空间是负值的时候此伸缩项目相对于伸缩容器里其他伸缩项目能伸缩的空间比例。在伸缩的时候伸缩比率会以伸缩基准值加权。

伸缩基准值 - flex-basis

设置伸缩基准值,剩余的空间按比率进行伸缩,也就是根据可伸缩比率计算出剩余空间的分布之前,伸缩项目主轴长度的起始数值。开始的时候你可以粗略的认为他是伸缩项目的长度。

可以看出来,在伸缩项目的伸缩基准值之和小于伸缩容器的主轴长度时,这个时候剩余空间是正值,伸缩比例是不起作用的,伸缩项目会按扩展比率分配掉剩余空间。在伸缩项目的伸缩基准值之和大于伸缩容器的主轴长度时,这个时候剩余空间是负值,扩展比例是不起作用的,伸缩项目会进行伸缩,伸缩量是根据伸缩比例和伸缩基准值计算出来的,具体的计算方法是酱紫的,伸缩项目的 伸缩比例 * 伸缩基准值所占权重乘以溢出量(溢出量,应该好理解,就是超出部分,剩余空间的相反数)

举几个栗子

  • 设置3个伸缩项目的flex-grow分别为1,2,3,那么他们就会按1:2:3来分配剩余空间,这里就是全部父元素–伸缩容器的空间900px,可以切换到 HTML 和 CSS 标签查看详情。
  • 设置3个伸缩项目的flex-grow分别为1,2,3,同时还设置flex-basis的值,那么他们就会按1:2:3来分配剩余空间,只是这里的剩余空间不是900px了,而是

剩余空间:900 - 200 - 50 - 50 = 600

1所占空间:200 + 1 / (1 + 2 + 3) * 600 = 300

2所占空间:50 + 2 / (1 + 2 + 3) * 600 = 250

3所占空间:50 + 3 / (1 + 2 + 3) * 600 = 350

  • 设置3个伸缩项目的flex-grow分别为1,2,3,flex-shrink分别为2,1,1,同时还设置flex-basis的值,各块大小详细的算法如下

剩余空间:900 - 600 - 400 - 200 = -300,那么溢出量是300,前面说过,FLexbox 是可伸缩的,所以这个300必须在内部消化掉,方案就是将这300分配到伸缩项目里面去!

1所占空间:600 - 2 * 600 / (2 * 600 + 1 * 400 + 1 * 200) * 300 = 400

2所占空间:400 - 1 * 400 / (2 * 600 + 1 * 400 + 1 * 200) * 300 = 333.3

3所占空间:200 - 1 * 200 / (2 * 600 + 1 * 400 + 1 * 200) * 300 = 167.7

可以发现我们这一步在计算的时候没有用到flex-grow,你在codepen编辑器里面改变他的值,显示出来的值是不变的,这个在上面我们已经提到过了。

对齐

在一个伸缩容器里面的伸缩项目完成排列和确定大小以后,那么就剩下对齐方式了。

主轴对齐 ―justify-content

justify-content属性用于在主轴上对齐伸缩项目。这一行为会在所有可伸缩长度及所有自动边距均被解释后进行。当一行上的所有伸缩项目都不能伸缩或可伸缩但是已经达到其最大长度时,这一属性才会对多余的空间进行分配。当项目溢出某一行时,这一属性也会在项目的对齐上施加一些控制。

  • flex-start:伸缩项目向一行的起始位置靠齐。该行的第一个伸缩项目在主轴起点边的外边距与该行在主轴起点的边对齐,同时所有后续的伸缩项目与其前一个项目对齐。
  • flex-end: 伸缩项目向一行的结束位置靠齐。该行的最后一个伸缩项目在主轴终点边的外边距与该行在主轴终点的边对齐,同时所有前面的伸缩项目与其后一个项目对齐。
  • center: 伸缩项目向一行的中间位置靠齐。该行的伸缩项目将相互对齐并在行中居中对齐,同时第一个项目与该行的在主轴起点的边的距离等同与最后一个项目与该行在主轴终点的边的距离(如果剩余空间是负数,则保持两端溢出的长度相等)。
  • space-between: 伸缩项目会平均地分布在一行里。如果剩余空间是负数,或该行只有一个伸缩项目,则此值等效于flex-start。在其它情况下,第一个项目在主轴起点边的外边距会与该行在主轴起点的边对齐,同时最后一个项目在主轴终点边的外边距与该行在主轴终点的边对齐,而剩下的伸缩项目在确保两两之间的空白空间相等下平均分布。
  • space-around:伸缩项目会平均地分布在行里,两端保留一半的空间。如果剩余空间是负数,或该行只有一个伸缩项目,则该值等效于center。在其它情况下,伸缩项目在确保两两之间的空白空间相等,同时第一个元素前的空间以及最后一个元素后的空间为其他空白空间的一半下平均分布。 具体的看图便知!

justify-content

侧轴对齐 ―align-itemsalign-self

伸缩项目可以在伸缩容器的当前行的侧轴上进行对齐,这类似于justify-content属性,但是是另一个方向。align-items可以用来设置伸缩容器中包括匿名伸缩项目的所有项目的对齐方式。align-self则用来在单独的伸缩项目上覆写默认的对齐方式。(对于匿名伸缩项目,align-self的值永远与其关联的伸缩容器的align-items的值相同。) 若伸缩项目的任一个侧轴上的外边距为auto,则align-self没有效果。 如果align-self的值为auto,则其计算值为元素的父元素的align-items值,如果该元素没有父元素,则计算值为stretch。对齐属性值的定义如下:

  • flex-start:伸缩项目在侧轴起点边的外边距紧靠住该行在侧轴起点的边。
  • flex-end:伸缩项目在侧轴终点边的外边距靠住该行在侧轴终点的边。
  • center:伸缩项目的外边距盒在该行的侧轴上居中放置。(如果伸缩行的尺寸小于伸缩项目,则伸缩项目会向两个方向溢出相同的量)。
  • baseline:如果伸缩项目的行内轴与侧轴为同一条,则该值与flex-start等效。 其它情况下,该值将参与基线对齐。所有参与该对齐方式的伸缩项目将按下列方式排列,首先:将这些伸缩项目的基线进行对齐,随后其中基线至侧轴起点边的外边距距离最长的那个项目将紧靠住该行在侧轴起点的边。
  • stretch:如果侧轴长度属性的值为auto,则此值会使项目的外边距盒的尺寸在遵照min/max-width/height属性的限制下尽可能接近所在行的尺寸。

Flex-align

堆栈伸缩行 ―align-content

当伸缩容器的侧轴还有多余空间时,align-content属性可以用来调准伸缩行在伸缩容器里的对齐方式,这与调准伸缩项目在主轴上对齐方式的justify-content属性类似。请注意本属性在只有一行的伸缩容器上没有效果。各属性值的意义如下:

  • flex-start:各行向伸缩容器的起点位置堆叠。伸缩容器中第一行在侧轴起点的边会紧靠住伸缩容器在侧轴起点的边,之后的每一行都紧靠住前面一行。
  • flex-end:各行向伸缩容器的结束位置堆叠。伸缩容器中最后一行在侧轴终点的边会紧靠住该伸缩容器在侧轴终点的边,之前的每一行都紧靠住后面一行。
  • center:各行向伸缩容器的中间位置堆叠。各行两两紧靠住同时在伸缩容器中居中对齐,保持伸缩容器在侧轴起点边的内容边和第一行之间的距离与该容器在侧轴终点边的内容边与第最后一行之间的距离相等。(如果剩下的空间是负数,则行的堆叠会向两个方向溢出的相等距离。)
  • space-between:各行在伸缩容器中平均分布。如果剩余的空间是负数或伸缩容器中只有一行,该值等效于flex-start。在其它情况下,第一行在侧轴起点的边会紧靠住伸缩容器在侧轴起点边的内容边,最后一行在侧轴终点的边会紧靠住伸缩容器在侧轴终点的内容边,剩余的行在保持两两之间的空间相等的状况下排列。
  • space-around:各行在伸缩容器中平均分布,在两边各有一半的空间。如果剩余的空间是负数或伸缩容器中只有一行,该值等效于center。在其它情况下,各行会在保持两两之间的空间相等,同时第一行前面及最后一行后面的空间是其他空间的一半的状况下排列。
  • stretch:各行将会伸展以占用剩余的空间。如果剩余的空间是负数,该值等效于flex-start。在其它情况下,剩余空间被所有行平分,扩大各行的侧轴尺寸。

align-content

因为年底有点事情,这篇博客终于在元旦假期写完了,祝新年快乐!

参考文献

  1. Css3-flexbox