图解CSS:Flexbox布局(Part1)

发布于 大漠

CSS布局发展至今可以说变化非常的大,其中Flexbox布局已经取代了以前最为流行的浮动布局。这里所说的Flexbox布局指的就是 CSS Flexible Box Module Level 1(简称Flexbox,弹性布局)。Flexbox模块的出现让Web的布局变得极为简单。虽然Flexbox给Web布局带来了很多优势,而且让布局变得简单,但就Flexbox模块本身来说是非常复杂。在这一章节中,我将和大家一起来探讨CSS的Flexbox 模块相关的知识。

Flexbox布局简介

Flexbox模块中的各功能主要用来服务于Web布局,就这方面而言,Flexbox是一种简单而强大的布局方式,通过Flexbox布局可以明确的指明容器空间的分布方式、内容对齐方式和元素的视觉顺序。使用Flexbox布局,可以轻易的实现横向或纵向布局,还可以沿着一个轴布局,或折断成多行。可以说,使用Flexbox模块给Web布局,可以轻易地你想要的任何布局效果。

另外,使用Flexbox模块来布局,还可以让Web内容的渲染顺序不再受HTML源码顺序的限制。然而,这只是视觉上的调整,Flexbox模块中的相关属性并不会改变屏幕阅读器对内容的读取顺序。

为什么说Flexbox模块复杂呢?主要是和以往的Web布局方式对比,甚至说和其他功能模块对比,Flexbox模块中涉及的到概念更多,更复杂,比如下图所示:

看到上图,是不是感觉很虚。其实不用过于担心,接下来的内容能很好的让你理解Flexbox

Flexbox模块中的术语

为了能更好的帮助大家理解和掌握Flexbox,我们有必要先从Flexbox模块中的术语出发。

Flexbox是一个完整的模块,而不是一个单独的属性,所以它会涉及很多东西,包括它的整个属性集。其中一些是要在容器上设置的(父元素,也常称Flex容器),而其他的是要在子元素上设置(子元素,也常称Flex项目)。

如果“常规”的布局(比如流行了很久的浮动布局),它是基于内联流方向,而Flexbox布局则是基于flex-flow方向。比如规范中提供的这张图,完美的阐述了Flexbox布局背后的主要思想:

上图所描述的其实也是Flexbox模块,同时Flexbox模块中所涉及到的技术术语也全体现出来了。

Flex容器和Flex项目

首先要理解的概念就是Flex容器(也被称之为弹性容器),其实它也是一个容器框。简单地说,在任一元素上显式设置了display的值为flexinline-flex,那么该容器就是一个Flex容器。这个时候为其子元素生成了一个弹性格式化上下文(也被称为FFC)。比如:

<!-- HTML -->

<flex-container>
    <伪元素> <文本内容> <HTML元素>
</flex-container>

也就是说,如果在<flex-container>元素上显式设置了:

.flex-container {
    display: flex;
}

// 或

.flex-container {
    display: inline-flex;
}

那么该元素就是Flex容器,而该元素的子元素(不管是DOM节点文本节点还是伪元素生成的内容)都会被称为“弹性元素”(也被称为Flex项目)。

有一点非常的重要,在Flexbox模块中,Flex容器和Flex项目之间的关系永远是父子关系。也就是说,只要有父子关系,就可以建立Flexbox。所以子元素也可以是它的子元素的Flex容器。但它将是一个单独的Flex容器。它不会继承祖辈的Flex属性。

主轴、主方向、侧轴和侧方向

在Flexbox模块中,Flexbox中有两个轴:主轴(Main Axis)侧轴(Cross Axis),同时也有两个方向,沿着主轴方向称为主方向,沿着侧轴方向称为 侧方向。其中主轴是定义Flex项目如何放置在Flex容器中的方向,一旦确定了主轴方向(主方向),那么侧轴方向(侧方向)就能很容易地确定,因为侧轴方向总是垂直于主轴方向。

熟悉Web开发的同学应该对Web的坐标系不会感到陌生,他有x轴、y轴和z轴,其中x轴永远都是水平的,y轴垂直的。如下图所示:

但在Flexbox模块中,主轴可以是水平的,也可以是垂直的,侧轴可以是垂直的,也可以是水平的。而且在Flexbox中,主轴和侧轴的方向和Flex容器属性中的flex-direction取值有着直接关系:

在Flexbox模块中,你仅仅看到的是flex-direction取值对主轴方向和侧轴方向的影响,其实放大到整个布局系统中来看的话,它还会受书写模式(writing-mode)、阅读方式(direction)以及容器的dir属性的影响。我们来看下面这个示例:

你可以尝试着调整示例中下拉选项中的值,可以看到排列和方向性是有差异的。这也印正了主轴方向和侧轴方向会随着writing-modedirection的值有所变化。

先来看flex-direction取值为rowrow-reverse随着writing-modedirection的变化:

再来看flex-direction取值为columncolumn-reverse随着writing-modedirection的变化:

简而言之,Flexbox模块中的主轴、主方向、侧轴和侧方向不是固定不变的,他们会随着writing-mode(书写模式)和direction(阅读方向)而改变

主轴起点、主轴终点、侧轴起点和侧轴终点

从上面我们可以看得出来,在Flexbox模块中,不管是主轴还是侧轴,都有方向性。既然有方向,就有开始处(即起点)和结束处(终点)。换句话说,在Flexbox模块中,主轴起始处称为主轴起点(Main Start),主轴终点处称为主轴终点(Main End);侧轴起始处称为侧轴起点(Cross Start),侧轴终点处称为侧轴终点(Cross End)

Flexbox模块中的主轴(或侧轴)起点、终点同样和writing-modedirection的取值有关。

上图向大家演示的是flex-direction取值为rowrow-reversewriting-modedirection取不同值时主轴(侧轴)起点、主轴(侧轴)终点位置。对于flex-direction取值为columncolumn-reverse同样会受writing-mode以及direction的影响。这里就不向大家示意了。

主长度和侧长度

这里所说的主长度是指主轴方向Flex容器的大小,即主轴起始点和主轴终点之间的距离;侧长度是指侧轴方向Flex容器的大小,即侧轴起始点和侧轴终点之间的距离。主长度和侧长度可以用来描述Flex容器的大小(widthheight),只不过,主长度和侧长度不是固定不变的,也就是说,主长度有可能是Flex容器的width,也有可能是Flex容器的height;同样的,侧长度有可能是Flex容器的height,也有可能是Flex容器的width。具体是Flex容器的width还是height,主要取决于flex-direction的取值,以及writing-modedirection的值。

上图演示的是flex-direction取值为rowrow-reversewriting-mode以及direction取值下的主长度和侧长度。

在CSS中我们可以使用物理属性或逻辑属性来描述Flex容器主长度和侧长度:

另外,如果没有在Flex容器上显式设置主长度和侧长度,那么将会有Flex项目的大小来决定。

Flexbox布局盒模型

在CSS中,任何一个元素都是一个框(盒子),具有相应的盒模型。这也是CSS中最基础,最重要的概念之一。对于Flexbox布局而言,也有一个盒模型的概念 —— Flexbox布局盒模型。简单地说:显式在元素上设置了display的值为flexblock flex)或inline-flexinline flex),该元素就是Flexbox布局盒模型,具有Flexbox布局特征

Flexbox布局盒模型和我们所说的CSS盒模型有所不同:CSS盒模型主要用来确定元素尺寸和位置;Flexbox布局盒模型主要用来描述Flexbox布局的特征

Flexbox布局盒模型主要由Flex容器Flex项目主轴侧轴(也被称为垂直轴)主方向侧方向主轴起点主轴终点侧轴起点侧轴终点主轴长度侧轴长度构成。比如W3C官网提供的示意图:

注意,上图向大家演示的是flex-direction: row,书写模式和阅读模式都是LTR的情况下的Flexbox布局盒模型。换句话说,Flexbox布局盒模型会随着flex-directionwriting-modedirectiontext-orientation以及HTML的dir属性的影响。比如下图展示的就是flex-direction: row || row-reversewriting-modedirection取值不同时Flexbox布局盒模型的变化:

在Flexbox布局中,Flexbox布局盒模型是非常的重要,它涵盖了所有Flexbox的特征。

运用于Flex容器(父容器)属性

有关于Flexbox布局的属性主要分为两部分,其一是运用于Flex容器(父元素);另一部分运用于Flex项目(子元素)。我们先来看运用于Flex容器上的属性:

display

在CSS中,可以通过display属性来改变元素上下文格式。在Flexbox布局中,如果我们显式的在某个元素上设置了display的值为flex(即block flex)或inline-flex(即inline flex),就创建了FFC(即“Flex Formatting Context”)。简单地说:

  • flexblock flex:让该元素产生块级Flex容器盒子
  • inline-flexinline flex:让该元素产生行内Flex容器盒子

在Flexbox布局中,块级Flex容器行内Flex容器统称为Flex容器。Flex容器会为其内容建立新的伸缩格式化上下文,即Flex Formatting Context

特别声明:在不久的将来,CSS的display可以接受两个值,正如上面示例中的block flexinline flex,特别是在布局的时候,显式的设置两个值,更有易于理解布局的方式

正如前面提到过,当在某个元素上显式设置display的值为flexinline-flex时,该元素就是一个Flex容器,其子元素(包括文本或伪元素)就成为Flex项目

Flex容器(特别是display:flex时)看上去像块容器(类似display: block),但事实上Flex容器不是块容器,因此有些运用在块容器(主要是指块布局)属性就不再适用于Flex容器(在Flexbox布局中不适用)。特别是:

  • CSS的 column-* 属性在Flex容器上不起作用
  • CSS的 float 和 **clear**属性在Flex项目上不起作用,也不会让Flex项目脱离文档流
  • CSS的 **vertical-align**属性在Flex项目上不起作用
  • CSS伪元素 ::first-line 和 **::first-letter**在Flex容器上不起作用,而且Flex容器不会为其祖先提供首行或首字母格式化

有一点需要注意,如果元素的display的值为inline-flex,并且该元素显式的设置了floatposition的值为relativeabsolutefixed,那么display的计算值是flex

flex-direction

在Flexbox布局中可以使用flex-direction指定主方向,用来指定Flex项目在Flex容器中的排列顺序(按方向布局)。前面我们也提到过了,Flexbox中的主方向可以是水平的,也可以垂直的。它由flex-direction的取值来决定,而且也受writing-modedirection等属性的影响。

Flexbox中的flex-direction的取值主要有:

flex-direction: row | row-reverse | column | column-reverse

其中row为初始值。

上图向大家展示的是flex-directionwriting-mode: horizontal-tbdirectionltrrtl组合在一起的效果。另外的组合不在这里展示,如果你感兴趣的话,可以尝试着修改下面Demoe中下拉选项框中的值:

注意,flex-direction取值决定的是Flex项目默认情况下Flex项目在Flex容器中的排序和方向,除此之外,在Flexbox布局模型中,Flex项目中的order属性也可以决定Flex项目在Flex容器的顺序,在后面的章节中我们会向大家演示

flex-wrap

Flexbox布局模型中的伸缩容器可以是单行的,也可以是多行的。这主要由flex-wrap属性决定。该属性可以取值:

flex-wrap: nowrap | wrap | wrap-reverse

每个属性值的含义如下:

  • nowrapflex-wrap的初始值。不换行,即伸缩容器为单行,即伸缩容器的所有子元素(Flex项目)在单独的一行上布局,如果Flex项目的内容总和超过容器的宽度(主长度),那么内容会溢出Flex容器
  • wrap:伸缩容器为多行
  • wrap-reverse:伸缩容器为多行,方向和wrap-reverse相反

flex-wrap取值为wrapwrap-reverse时,伸缩容器为多行,也就是说Flex项目当在Flex容器一行中无法排列时,会另起一行排列(这有点类似于文本在容器边缘断行排列一样)。

如果你在上例中对下拉选择项做不同的选择,不难发现flex-wrap的效果同样受writing-modedirection等属性的影响。比如:

上图向大家展示的是writing-mode:horizontal-tbdirection:ltrflex-direction以及flex-wrap取不同值时,伸缩项目在伸缩容器中的排列方向。

flex-flow

flex-flowflex-directionflex-wrap的简写属性:

flex-flow: <flex-direction> || <flex-wrap>

两个属性值决定了伸缩方向和换行,同时也决定了伸缩容器的主轴与侧轴。

在使用flex-flow时也可以只显式的设置<flex-direction><flow-wrap>其中一个值,如果其中某个值缺省不显式设置,则将取其默认值,即其初始值:

flex-flow: row            »»»  flex-flow: row nowrap
flex-flow: column         »»»  flex-flow: column nowrap
flex-flow: row-reverse    »»»  flex-flow: row-reverse nowrap
flex-flow: column-reverse »»»  flex-flow: column-reverse nowrap
flex-flow: nowrap         »»»  flex-flow: row nowrap
flex-flow: wrap           »»»  flex-flow: row wrap
flex-flow: wrap-reverse   »»»  flex-flow: row wrap-reverse

justify-content

justify-content属性用于在主轴上对齐Flex项目。这一行为会在所有可伸缩长度及所有自动边距均被解释后进行。通常情况下,当一行上的所有Flex项目都不能伸缩或已达到其最大值时,这一属性可协助对Flex容器剩余空间进行分配。当元素溢出某行时,这一属性同样会在对齐上施加一些控制。

justify-content目前存在W3C两个功能模块中,其中第一个模块是 CSS Flexible Box Layout Module Level 1,在该模块中定义的justify-content属性主要接受:

justify-content: flex-start | flex-end | center | space-between | space-around

第二个是存于 CSS Box Alignment Module Level 3 模块中,在这个模块中新增加了startendleftright

justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly | start | end | left | right 

请注意,浏览器对这些值的支持有细微的差别

接下来,我们来看看这些值具体的效果。

flex-start

flex-startjustify-content的初始值(默认值)。Flex项目向主轴起点位置靠齐,即行上第一个Flex项目起始位置和Flex容器主轴起点位置平齐:

flex-end

flex-end的表现行为和flex-start刚好相反。Flex项目向主轴终点位置靠齐,即行上最后一个Flex项目的终点位置和Flex容器主轴终点位置平齐:

center

所有Flex项目沿着主轴方向在Flex容器中居中靠齐,同时第一个Flex项目起始位置距离Flex容器主轴起点距离等同于最后一个Flex项目终点位置距离Flex容器主轴终点距离。

space-between

Flex容器主轴方向剩余的空间会平均分布在Flex项目之间。如果有多个Flex项目沿着主轴方向排列,第一个Flex项目起始点和主轴起点平齐(没有任何空间)以及最后一个Flex项目终点和主轴终点平齐(没有任何空间),剩下的空间平均分配在Flex项目之间,并且确保两两之间空白空间(间距)相等

当Flex容器中只有一个Flex项目或者Flex容器没有额外的剩余空间,那么space-between的表现行为和flex-start相同:

space-around

space-around有点类似于space-between,Flex项目会平均地分布在Flex容器主轴方向,即Flex容器主轴方向的剩余空间分平均地分布在Flex项目之间。如果有多个Flex项目,Flex项目两两之间的间距是相等的,其中第一个Flex项目超始点和Flex容器主轴起点之间间距是相邻两个Flex项目之间间距的一半;同样最后一个Flex项目终点和Flex容器主轴终点之间的间距也是相邻两个Flex项目之间的一半。

如果Flex容器中只有一个Flex项目或者所有Flex项目主轴方向尺寸总和大小Flex容器主轴长度(也就是说Flex容器没有剩余的空间,即剩余空间是负数),那么space-around的表现形为类似于center:

space-evenly

Flex容器主轴剩余空间平均分布在Flex项目之间,而且第一个Flex项目的起始点距Flex容器主轴起点间距和Flex项目两两之间相等,同时最后一个Flex项目终点距离Flex容器主轴终点之间间距也和Flex项目两两之间相等。

如果Flex容器只有一个Flex项目或者Flex容器主轴剩余空间为负值,那么space-evenly的表现形为和center类似。

space-between vs. space-around vs. space-evenly

justify-content中的space-betweenspace-aroundspace-evenly有一个共性,都是用来对Flex容器主轴剩余空间进行分配,并且Flex项目两两之间都是均分,它们之间的不同之处是分配剩余空间略有差异,即Flex容器有多个Flex项目时,并且有剩余空间,那么第一个Flex项目起点至Flex容器主轴起点间距以及最后一个Flex项目终点距Flex容器主轴终点之间间距的分配模式不同

  • space-between:第一个Flex项目起点距Flex容器主轴起点之间没有任何空白间距;最后一个Flex项目终点距Flex容器主轴终点之间没有任何空白间距
  • space-around:第一个Flex项目起点距离Flex容器主轴起点之间的空白间距是两个相邻Flex项目之间空白间距的一半;最后一个Flex项目终点距Flex容器主轴终点之间空白间距是两个相邻Flex项目之间空白间距的一半
  • space-evenly:第一个Flex项目起点距离Flex容器主轴起点之间的空白间距和两个相邻Flex项目之间空白间距相等;最后一个Flex项目终点距Flex容器主轴终点之间空白间距和两个相邻Flex项目之间空白间距相等

来看一个示例:

剩余空间的均分情况如下图标注的一样:

只有Flex容器主轴方向有剩余空间时,才会有间距存在,如果Flex容器主轴方向剩余空间为负值或者Flex容器中只有一个Flex项目,共中space-between表现行为类似于flex-startspace-aroundspace-evenly的表现行为类似于center

startleftendright

CSS Box Alignment Module Level 3 模块中 justify-content属性新增了startendleftright。它们和我们前面所了解的flex-startflex-end等值有所不同,这几个和 块轴(Block Axis) 和 **行内轴(Inline Axis)**的关系更紧密。

有关于这方面更详细的介绍,可以阅读《图解CSS:CSS逻辑属性》一文。

其中leftright是我们熟悉的属性(即物理属性),早期一般只运用于position这样的定位属性上,而startend是CSS的逻辑属性,它们和书写模式writing-mode和阅读方式direction有关。再回到Flexbox布局模型中来,justify-content的值都是用来控件Flex容器中的Flex项目在主轴方向的排列方式(Flex容器剩余空间的分布)。

请使用Firefox浏览器查看,到目前为止只在Firefox支持

上图演示的是direction: ltrwriting-mode: horizontal-tbflex-direction: rowjustify-content取值为flex-startflex-endstartendleftend的效果。前面的示例告诉我们,justify-content的渲染结果和directionwriting-mode以及flex-direction有着紧密的关系,而其中 start 和 **end**这样的CSS逻辑属性和direction以及writing-mode的关系更紧密。

另外,这几个属性的组合,最终渲染的效果如下:

align-items

align-itemsjustify-content类似,都是用来控制Flex项目在Flex容器中对齐方式(即分配Flex容器剩余空间),不同的是justify-content是用来控制Flex容器主轴方向的对齐方式,而align-items是用来控制Flex容器侧轴方向的对齐方式。

align-items: stretch | flex-start | flex-end | center | baseline | first baseline | last baseline | start | end | self-start | self-end

其中first baselinelast baselinestartendself-startself-end是来自于 CSS Box Alignment Module Level 3 模块中。

到目前为止,其中 CSS Box Alignment Module Level 3 模块引入的值仅在Firefox浏览器支持部分属性。而且align-items同样受directionwriting-mode的影响,不过为了能节约更多的时候和篇幅,这一节不会将directionwriting-mode所有的场景覆盖,仅以direction: ltrwriting-mode:horizontal-tb为例。

stretch

stretchalign-items的初始值(默认值)。如果Flex项目未显式的设置大小尺寸,那么Flex项目会沿着Flex容器侧轴方向拉伸以填满Flex容器侧轴方向(和Flex容器侧轴尺寸相等)。

但如果在Flex项目上显式的设置了width(或inline-size)、height(或block-size)、max-width(或max-inline-size)或max-height(或max-block-size),即使Flex容器显式设置了align-items的值为stretch,Flex项目也不会沿着Flex容器侧轴拉伸:

flex-start

align-items取值flex-start会使Flex项目侧轴起始点和Flex容器侧轴起始点平齐:

flex-end

flex-end的表现行为和flex-start刚好相反。如果align-items取值为flex-end时,Flex项目侧轴的终点和Flex容器侧轴终点平齐:

center

align-items取值为center时,Flex项目侧轴起始点距离Flex容器侧轴起始点位置和Flex项目侧轴终点距离Flex容器侧轴终点位置相等,即Flex项目在Flex容器侧轴上居中对齐:

注意,如果Flex容器侧轴尺寸小于Flex项目的侧轴的尺寸,则Flex项目会沿着Flex容器侧轴向两个方向扩展,并且会溢出Flex容器。

baseline

align-items取值为baseline时,Flex项目在Flex容器侧轴方向会根据Flex项目文本的baseline为对齐的基准。即Flex项目行以Flex项目文本的baseline为基准。所有参与该对齐方式的Flex项目将按一定方式排列,首先将它们的基线baseline进行对齐,随后其中基线至其侧轴起始位置的边距边界(侧轴起始点)距离最长的那的个Flex项目将紧靠住该行的侧轴起始边界。如查Flex项目的baseline和Flex容器侧轴在同一条(平行),那么baseline的表现行为和flex-start相同:

注意,在未来align-items除了使用baseline之外还有first baselinelast baseline。它们统一称为<baseline-position>。这部分更详细的阐述将放到CSS的书写模式中来阐述。

startend

startend同样是CSS逻辑属性带来的概念,它们和writing-mode以及direction的关系更为紧密。如果align-items取值为start时,Flex项目侧轴起点和Flex容器的block-start平齐;同样的,align-items取值为end时,Flex项目侧轴终点和Flex容器的block-end平齐:

上图,我们看到的只是writing-mode: horizontal-tbflex-direction: row | row-reversedirection: ltr | rtl不同组合下Flex项目在Flex容器的侧轴排列方式。其他的组合可以尝试着调整下面Demo中的选项:

self-startself-end

self-startstart的表现行为相似;self-endend的表现行为相似:

align-content

在Flexbox布局中有的时候可能会多行或多列显示,换句话说,Flex容器没有足够空间容纳Flex项目,同时flex-direction的值为wrapwrap-reverse时,Flex项目会在Flex容器中断行排列(换行或换列排列)。而align-content属性主要用来控制Flex容器侧轴方向多行(或多列)时的排列方式,简单地说,当Flex容器有剩余空间,并且Flex项目在Flex容器多行(或多列)排列时,align-content主要用来控制Flex容器侧轴方向剩余空间在行(或列)之间的分布。该属性与justify-content属性用于在Flex容器主轴上对齐独立的Flex项目类似:

align-content: flex-start | flex-end | center | space-between | space-around | space-evenly | stretch | start | end | baseline | first baseline | last baseline

flex-start

Flex容器侧轴方向中第一行的侧轴起始边界紧靠住该Flex容器的侧轴起点边界,之后的每一行都紧靠前面一行:

上图仅展示的是direction: ltr || rtlwriting-mode: horizontalp-tbflex-flow: row wrap || row wrap-reverse || row-reverse wrap || row-reverse wrap-reverse || column wrap || column wrap-reverse || column-reverse wrap || column-reverse wrap-reverse组合下align-content取值为flex-start的渲染结果。

flex-end

align-content取值为flex-end刚好和flex-start相反。Flex容器中最后一行的Flex项目侧轴方向终点边界紧靠住该Flex容器侧轴终点边界,之后的每一行都紧靠住前面一行。

center

align-content取值为center时,Flex容器中所有行的Flex项目排列在Flex容器侧轴方向中间,即Flex容器第一行Flex项目的起始位置距离Flex容器侧轴起点位置距离等于最后一行Flex项目的终点位置距离Flex容器侧轴终点位置距离。

当Flex容器侧轴长度小于Flex容器所有Flex项目行侧轴长度之和,即Flex容器侧轴有没空余的空间(Flex容器侧轴剩余空间为负数)时,则各行会向两个方向溢出相等距离:

space-between

align-content取值为space-between时,Flex容器中Flex项目两两行之间的间距相等,即第一行Flex项目侧轴起始边界紧靠Flex容器侧轴起始边界(间距为0),同时最后一行Flex项目侧轴终点边界紧靠Flex容器侧轴终点边界,剩余的Flex行则按一定的方式在Flex容器侧轴中排列,并且两两之间间距相等:

如果Flex容器的Flex项目只有一行或者说Flex容器的剩余空间为负值时,space-between的表现行为和flex-start相似:

sapce-around

align-content取值space-around时,Flex容器中侧轴方向所有Flex项目行与行之间的距离相等,并且第一行Flex项目侧轴起点边界与Flex容器侧轴起始边界之间的距离等于Flex容器最后一行Flex项目侧轴终点边界与Flex容器侧轴终点边界之间的间距,同时是其他相邻两行之间间距的一半:

如果Flex容器中只有一行Flex项目或者Flex容器侧轴方向的剩余空间为负值,那么space-around的表现行为和center相似。

space-evenly

align-content取值为space-evenly时,Flex容器侧轴方向的所有Flex项目行之间的间距相等,并且第一行Flex项目侧轴起始边界距离Flex容器侧轴起始办界的间距与最后一行Flex项目终点边界距离Flex容器侧轴终点边界的间距相等,同时也等于行与行之间的空白间距:

如果Flex容器只有一行Flex项目或者说Flex容器侧轴方向的剩余空间为负值时,space-evenly的表现行为和center相似。

stretch

align-content取值为stretch时,如果Flex容器侧轴方向有剩余空间的话将会把剩余空间均分给Flex容器侧轴方向的所有Flex项目行,这个时候Flex项目会沿着侧轴方向拉伸:

如果Flex容器剩余空间是负值,该值等效于flex-start

startend

align-content取值为startend时和CSS的writing-modedirection联系的更为紧密。

place-content

place-contentalign-contentjustify-content的简写属性,即同时具备align-contentjustify-content特性:

place-content: <align-content> <justify-content>?

主要用来控制Flex容器中Flex行在侧轴的排列和Flex项目在主轴的排列方式(即Flex容器剩余空间的分配):

你可以尝试着调整上面示例中place-content对应的值。在使用place-content属性时可以显式的设置两个值,比如:

.container {
    place-content: space-between center
}

上面的代码等效于:

.container {
    align-content: space-between;
    justify-content: center;
}

也可以显式设置一个值:

.container {
    place-content: space-between;
}

如果place-content仅显式设置一个属性值,则align-contentjustify-content属性的值相同。上面示例代码等效于:

.container {
    align-content: space-between; 
    justify-content: space-between;
}

gap

gap属性是具有戏剧性的一个CSS属性。这里所说的gap指的是间距,即列与列行与行 之间的间距。在这个属性出来之前,往往都是使用margin来控制的,但是使用margin来控制列与列(或行与行)之间的间距,会存在不少的问题。比如我们实现像下图这样的UI效果:

如果用margin的话会让元素与容器之间存有不必要的空白:

有了gap属性就可以实现所需要的UI效果。

先抛开如何实现所需要的UI效果,继续了解gap属性。在CSS中,最早出现和gap有关的属性是 CSS Multi-column Layout Module Level 1column-gap属性,主要用来控制多列布局中列与列之间的间距。随着CSS Grid 布局的到来,在CSS Grid布局中也提出了间距的概念,即grid-column-gapgrid-row-gap 分别控制列与列,行与行之间的间距。不过CSS Grid规范的制定者立马意识到,grid-column-gapgrid-row-gap对于开发者的学习而言,是不友好的,一样的作用,一样的语义,使用不同的名称。如果按照这个套路来制定规范的话,是不是在Flexbox布局中会有可能会产生一个flex-column-gapflex-row-gap属性。基于这个原因,在CSS Grid中开始放弃了grid-column-gapgrid-row-gap,重新声明了新的两个属性,那就是column-gaprow-gap(合在一起就是gap)。

随着相关规范不断的迭代更新和完善,gap属性后来被规划到 CSS Box Alignment Module Level 3 模块中:

row-gap: normal | <length-percentage>
column-gap: normal | <length-percentage>

而且它们还可以简写成gap

gap: <row-gap><column-gap>?

其中<column-gap>是可选的,如果gap只显式设置一个值,那么表示<column-gap><row-gap>的值相同。

很快,Flexbox布局中也引入了gap属性,并且得到了Firefox浏览器的支持。在Flexbox布局模块中,gap属性用在Flex容器上,主要用来控制Flex项目与Flex项目之间的间距:

.flex-container {
    gap: 20px;
}

在Firefox浏览器下,你将看到的效果如下:

你是不是也在想,如果不使用gap 属性在Flexbox布局中又怎么实现类似的效果呢?其实这并不难,只是麻烦一点。比如下面这个Demo:

示例很简单,这里着重拿margin的为例,其HTML结构如下:

<div class="container">
    <div class="flex__container flex__container--margin" data-gutter="margin">
        <div class="flex__item"></div>
        <div class="flex__item"></div>
        <div class="flex__item"></div>
        <div class="flex__item"></div>
        <div class="flex__item"></div>
        <div class="flex__item"></div>
        <div class="flex__item"></div>
        <div class="flex__item"></div>
    </div>
</div>

关键的CSS代码如下:

.container {
    display: flex;
    justify-content: center;
    align-items: center;

    width: calc(48vh + var(--gap) * 3 + 2px);
    border: 1px dashed #fff;
}

.flex__container {
    display: inline-flex;
    flex-flow:var(--flexDirection) var(--flexWrap);
    place-content: var(--alignContent) var(--justifyContent);
}

.flex__container--margin {
    margin: calc(-1 * var(--gap)) 0 0 calc(-1 * var(--gap));
    width: calc(100% + var(--gap));
}

.flex__container--margin > .flex__item {
    margin: var(--gap) 0 0 var(--gap);
}

.flex__container--gap {
    gap: var(--gap);
}

在Chrome浏览器和Firefox浏览器下看到的效果如下:

青蛙在Flexbox中...

上面我们看到的是能应用于Flexbox布局模块中属性。在社区中也有很多小游戏帮助我们用趣味性来帮助大家理解这些属性在Flexbox布局中的使用。这里也简单的构建一个小Demo,希望能更好的帮助大家理解上面的相关属性:

如果您仔细阅读到这里,说明你对Flexbox布局模块还是非常感兴趣。如果你想深入了解Flexbox布局模块中运用于Flex项目的属性以及Flex项目计算相关的原理,那么建议您点击这里继续阅读第二部分