34

写给自己看的display: flex布局教程

 5 years ago
source link: https://www.zhangxinxu.com/wordpress/2018/10/display-flex-css3-css/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

byzhangxinxu from https://www.zhangxinxu.com/wordpress/?p=8063

本文可全文转载,但需得到原作者书面许可,同时保留原作者和出处,摘要引流则随意。

//zxx: 本教程所有布局效果(含交互)为实时渲染,若布局异常,可以点击这里访问原文。

一、前言&索引

给div这类块状元素元素设置 display:flex 或者给span这类内联元素设置 display:inline-flex ,flex布局即创建!其中,直接设置 display:flex 或者 display:inline-flex 的元素称为flex容器,里面的子元素称为flex子项。

而Flex布局相关属性正好分为两拨,一拨作用在flex容器上,还有一拨作用在flex子项上。具体参见下表,点击可快速索引。

作用在flex容器上 作用在flex子项上

无论作用在flex容器上,还是作用在flex子项,都是控制的flex子项的呈现,只是前者控制的是整体,后者控制的是个体。

其他说明:

  • 本教程所有案例HTML结构为:

    container(flex容器)
      div(flex子项) > img
      div(flex子项) > img
      div(flex子项) > img

    同时,为了便于区分,flex容器区域使用虚框标示,flex子项增加了白蓝径向渐变背景色,图片上显示了原始序号。

  • Flex布局中还有主轴和交叉轴的概念,为避免过多概念干扰,本教程省略相关措辞,而是使用水平方向和垂直方向代替 ①

    //zxx: ① writing-mode属性可以改变文档流方向,此时主轴是垂直方向,但实际开发很少遇到这样场景,因此,初学的时候,直接使用水平方向和垂直方向理解不会有任何问题,反而易于理解。

二、作用在flex容器上的CSS属性

1. flex-direction

flex-direction 用来控制子项整体布局方向,是从左往右还是从右往左,是从上往下还是从下往上。和CSS的direction属性相比就是多了个 flex

语法如下:

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

其中:

row 默认值,显示为行。方向为当前文档水平流方向,默认情况下是从左往右。如果当前水平文档流方向是 rtl (如设置 direction:rtl ),则从右往左。 row-reverse 显示为行。但方向和 row 属性值是反的。 column 显示为列。 column-reverse 显示为列。但方向和 column 属性值是反的。

眼见为实,点击下面对应单选项,可以看到实时的布局效果:

RJ3yAn.jpg!web
7nMvIjN.jpg!web

2. flex-wrap

flex-wrap 用来控制子项整体单行显示还是换行显示,如果换行,则下面一行是否反方向显示。这个属性比较好记忆,在CSS世界中,只要看到单词wrap一定是与换行显示相关的, word-wrap 属性或者 white-space:nowrap 或者 pre-wrap 之类。

语法如下:

flex-wrap: nowrap | wrap | wrap-reverse;

其中:

nowrap
默认值,表示单行显示,不换行。于是很容易出现宽度溢出的场景,其渲染表现比较复杂,需要对CSS3宽度有一定了解,可以阅读“ 理解CSS3 max/min-content及fit-content等width值 ”这篇文章。具体表现如下(以水平布局举例):
  • flex子项最小内容宽度 min-content 之和大于flex容器宽度,则内容溢出,表现和 white-space:nowrap 类似。
  • 如果flex子项最小内容宽度 min-content 之和小于flex容器宽度,则:
    • flex子项默认的 fit-content 宽度之和大于flex容器宽度,则flex子项宽度收缩,正好填满flex容器,内容不溢出。
    • flex子项默认的 fit-content 宽度之和小于flex容器宽度,则flex子项以 fit-content 宽度正常显示,内容不溢出。

在下面案例中,示意的图片默认有设置 max-width:100% ,flex子项div没有设置宽度,因此,flex子项最小宽度是无限小,表现为图片宽度收缩显示。如果我们取消 max-width:100% 样式,则此时flex子项最小宽度就是图片宽度,就可以看到图片溢出到了flex容器之外。

wrap 宽度不足换行显示。 wrap-reverse 宽度不足换行显示,但是是从下往上开始,也就是原本换行在下面的子项现在跑到上面。

眼见为实,点击下面对应单复选框,可以看到实时的布局效果:

img{max-width:100%;}

RJ3yAn.jpg!web
7nMvIjN.jpg!web
UBvYver.jpg!web

3. flex-flow

flex-flow 属性是 flex-directionflex-wrap 的缩写,表示flex布局的flow流动特性,语法如下:

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

当多属性同时使用的时候,使用空格分隔。

举个例子,容器元素如下设置:

.container {
    display: flex;
    flex-flow: row-reverse wrap-reverse;
}

实时效果如下:

RJ3yAn.jpg!web
7nMvIjN.jpg!web
UBvYver.jpg!web

可以看到水平排序从右往左( row-reverse 属性值的作用),以及换行的那一行在上面( wrap-reverse 属性值的作用)。

4. justify-content

justify-content 属性决定了水平方向子项的对齐和分布方式。CSS text-align 有个属性值为 justify ,可实现两端对齐,所以,当我们想要控制flex元素的水平对齐方式的时候,记住 justify 这个单词, justify-content 属性也就记住了。

justify-content 可以看成是 text-align 的远房亲戚,不过前者控制flex元素的水平对齐外加分布,后者控制内联元素的水平对齐。

语法如下:

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

其中:

flex-start 默认值。逻辑CSS属性值,与文档流方向相关。默认表现为左对齐。 flex-end 逻辑CSS属性值,与文档流方向相关。默认表现为右对齐。 center 表现为居中对齐。 space-between
表现为两端对齐。between是中间的意思,意思是多余的空白间距只在元素中间区域分配。使用抽象图形示意如下:

vQbEBbj.png!web

space-around
around是环绕的意思,意思是每个flex子项两侧都环绕互不干扰的等宽的空白间距,最终视觉上边缘两侧的空白只有中间空白宽度一半。使用抽象图形示意如下:

ZBRrIn7.png!web

space-evenly
evenly是匀称、平等的意思。也就是视觉上,每个flex子项两侧空白间距完全相等。使用抽象图形示意如下:

2eY3mu2.png!web

眼见为实,点击下面对应单复选框,可以看到实时的布局效果:

direction:rtl(测试flex-start/flex-end)

RJ3yAn.jpg!web
7nMvIjN.jpg!web

5. align-items

align-items 中的 items 指的就是flex子项们,因此 align-items 指的就是flex子项们相对于flex容器在垂直方向上的对齐方式,大家是一起顶部对齐呢,底部对齐呢,还是拉伸对齐呢,类似这样。

语法如下:

align-items: stretch | flex-start | flex-end | center | baseline;

其中:

stretch 默认值。flex子项拉伸。在演示中我们可以看到白蓝径向渐变背景区域是上下贯穿flex容器的,就是因为flex子项的高度拉伸到容器高度导致。如果flex子项设置了高度,则按照设置的高度值渲染,而非拉伸。 flex-start 逻辑CSS属性值,与文档流方向相关。默认表现为容器顶部对齐。 flex-end 逻辑CSS属性值,与文档流方向相关。默认表现为容器底部对齐。 center 表现为垂直居中对齐。 baseline 表现为所有flex子项都相对于flex容器的基线(字母x的下边缘)对齐。

眼见为实,点击下面对应单选框,可以看到实时的布局效果:

x
RJ3yAn.jpg!web
7nMvIjN.jpg!web

6. align-content

align-content 可以看成和 justify-content 是相似且对立的属性, justify-content 指明水平方向flex子项的对齐和分布方式,而 align-content 则是指明垂直方向每一行flex元素的对齐和分布方式。如果所有flex子项只有一行,则 align-content 属性是没有任何效果的。

语法如下:

align-content: stretch | flex-start | flex-end | center | space-between | space-around | space-evenly;

其中:

stretch 默认值。每一行flex子元素都等比例拉伸。例如,如果共两行flex子元素,则每一行拉伸高度是50%。 flex-start 逻辑CSS属性值,与文档流方向相关。默认表现为顶部堆砌。 flex-end 逻辑CSS属性值,与文档流方向相关。默认表现为底部堆放。 center 表现为整体垂直居中对齐。 space-between 表现为上下两行两端对齐。剩下每一行元素等分剩余空间。 space-around 每一行元素上下都享有独立不重叠的空白空间。 space-evenly 每一行元素都完全上下等分。

眼见为实,我们给flex容器设置高度500像素,然后点击下面对应单选框,可以看到实时的布局效果:

RJ3yAn.jpg!web
7nMvIjN.jpg!web
UBvYver.jpg!web
vuaYvuM.jpg!web
Ibye6vv.jpg!web
MJreUrv.jpg!web

三、作用在flex子项上的CSS属性

1. order

我们可以通过设置 order 改变某一个flex子项的排序位置。

语法:

order: <integer>; /* 整数值,默认值是 0 */

所有flex子项的默认 order 属性值是0,因此,如果我们想要某一个flex子项在最前面显示,可以设置比0小的整数,如 -1 就可以了。

眼见为实,下面flex容器有3个子元素,现在,我们给第2个子元素设置 order 属性值,看看其排列位置有何变化。点击下面的单选框,可以看到实时的交互效果:

RJ3yAn.jpg!web
7nMvIjN.jpg!web

2. flex-grow

flex-grow 属性中的grow是扩展的意思,扩展的就是flex子项所占据的宽度,扩展所侵占的空间就是除去元素外的剩余的空白间隙。

具体的扩展比较复杂。在展开之前,我们先看下语法。

语法:

flex-grow: <number>; /* 数值,可以是小数,默认值是 0 */

flex-grow 不支持负值,默认值是0,表示不占用剩余的空白间隙扩展自己的宽度。如果 flex-grow 大于0,则flex容器剩余空间的分配就会发生,具体规则如下:

  • 所有剩余空间总量是1。
  • 如果只有一个flex子项设置了 flex-grow

    属性值:

    flex-grow
    flex-grow
    

    具体可参见下面“grow案例1”。

  • 如果有多个flex设置了 flex-grow

    属性值:

    • 如果 flex-grow 值总和小于1,则每个子项扩展的空间就总剩余空间和当前元素设置的 flex-grow 比例的计算值。
    • 如果 flex-grow 值总和大于1,则所有剩余空间被利用,分配比例就是 flex-grow 属性值的比例。例如所有的flex子项都设置 flex-grow:1 ,则表示剩余空白间隙大家等分,如果设置的 flex-grow 比例是1:2:1,则中间的flex子项占据一半的空白间隙,剩下的前后两个元素等分。

    具体可参见下面“grow案例2”。

grow案例1:

flex容器有3个子元素,现在,我们仅给第2个子元素设置 flex-grow 属性值,看看其占据尺寸有何变化。点击下面的单选框,可以看到实时的交互效果:

RJ3yAn.jpg!web
7nMvIjN.jpg!web

此实例演示中,仅一个flex子项设置了 flex-grow 属性值,当我们选择 0.5 的时候,值小于1,剩余空间用不完,因此,扩展的宽度是总剩余宽度是0.5,也就是一半;当我们选择 1 的时候,正好所有空间都使用;当我们选择 2 的时候,效果一样,因为没有其他参与分配的子项,因此渲染表现和 1 一样。

grow案例2:

flex容器有3个子元素,默认所有子项都设置了 flex-grow:0.25 ,现在我们点击下面的单选框,改变第2个子元素的 flex-grow 属性值,看看其占据尺寸有何变化:

RJ3yAn.jpg!web
7nMvIjN.jpg!web

此实例演示中,因为3个子项都是0.25,因此默认还剩余25%的剩余空间;如果我们选择 flex-grow:0 ,则加起来的 flex-grow0.5 ,因此剩余50%空间;如果我们选择 flex-grow:0.5 ,则加起来的 flex-grow1 ,因此没有剩余空间,同时空间占用比例为1:2:1,最终效果符合此预期;如果我们选择 flex-grow:1 ,则加起来的 flex-grow 大于 1 ,剩余空间按比例分配,为1:4:1,最终效果也确实如此。

以上就是 flex-grow 属性的作用规则。

3. flex-shrink

shrink是“收缩”的意思, flex-shrink 主要处理当flex容器空间不足时候,单个元素的收缩比例。

语法如下:

flex-shrink: <number>; /* 数值,默认值是 1 */

flex-shrink 不支持负值,默认值是1,也就是默认所有的flex子项都会收缩。如果设置为0,则表示不收缩,保持原始的 fit-content 宽度。

flex-shrink 的内核跟 flex-grow 很神似, flex-grow 是空间足够时候如何利用空间, flex-shrink 则是空间不足时候如何收缩腾出空间。总有点CP的味道。

两者的规则也是类似。已知flex子项不换行,且容器空间不足,不足的空间就是“完全收缩的尺寸”:

  • 如果只有一个flex子项设置了 flex-shrink
    flex-shrink
    flex-shrink
    
  • 如果多个flex子项设置了 flex-shrink
    • flex-shrink 值的总和小于1,则收缩的尺寸不完全,每个元素收缩尺寸占“完全收缩的尺寸”的比例就是设置的 flex-shrink 的值。
    • flex-shrink 值的总和大于1,则收缩完全,每个元素收缩尺寸的比例和 flex-shrink 值的比例一样。下面案例演示的就是此场景。

眼见为实,flex容器有4个子元素,现在,我们给第2个子元素设置不同的 flex-shrink 属性值,看看其占据尺寸有何变化。点击下面的单选框,可以看到实时的交互效果:

RJ3yAn.jpg!web
7nMvIjN.jpg!web
UBvYver.jpg!web

此实例演示中,因为4个子项都是1,和远大于1,因此,完全收缩,不会有内容溢出。如果我们选择 flex-shrink:0 ,则第2个flex子项不收缩,剩下3个flex子项等比例收缩;如果我们选择 flex-grow:1 ,则4个子项1:1:1:1收缩;如果我们选择 flex-grow:2 ,则完全收缩尺寸比例分配为1:2:1:1,第2个flex子项收缩的宽度最大,是其他元素的2倍。

以上就是 flex-shrink 属性的作用规则。

4. flex-basis

flex-basis 定义了在分配剩余空间之前元素的默认大小。相当于对浏览器提前告知:浏览器兄,我要占据这么大的空间,提前帮我预留好。

语法如下:

flex-basis: <length> | auto; /* 默认值是 auto */

默认值是 auto ,就是自动。有设置 width 则占据空间就是 width ,没有设置就按内容宽度来。

如果同时设置 widthflex-basis ,就渲染表现来看,会忽略 width 。flex顾名思义就是弹性的意思,因此,实际上不建议对flex子项使用 width 属性,因为不够弹性。

当剩余空间不足的时候,flex子项的实际宽度并通常不是设置的 flex-basis 尺寸,因为flex布局剩余空间不足的时候默认会收缩。

实例一则:

flex容器有3个子元素,现在,我们给第2个子元素设置不同的 flex-basis 属性值,看看其占据尺寸有何变化。点击下面的单选框,可以看到实时的交互效果:

RJ3yAn.jpg!web
7nMvIjN.jpg!web

选择最后一个 flex-basis:256px 会发现flex子项的宽度并不是 256px ,这是因为此时剩余空间不足,3个子项1:1:1收缩的缘故。

5. flex

flex 属性是 flex-growflex-shrinkflex-basis 的缩写。

语法:

flex: none | auto | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]

其中第2和第3个参数( flex-shrinkflex-basis )是可选的。默认值为 0 1 auto

案例演示:

第2个flex子项设置 flex:none 或者 flex:auto ,我们看看实时布局效果会有怎样的变化:

隐藏部分图片使空间剩余(为了测flex-grow)

RJ3yAn.jpg!web
7nMvIjN.jpg!web
UBvYver.jpg!web

此时第2个flex子项的 flex-growflex-shrinkflex-basis 属性值分别是 01 ,和 auto

经过上面一番测试,我们可以得到如下结论:

  • flex 默认值等同于 flex:0 1 auto
  • flex:none 等同于 flex:0 0 auto
  • flex:auto 等同于 flex:1 1 auto

6. align-self

align-self 指控制单独某一个flex子项的垂直对齐方式,写在flex容器上的这个 align-items 属性,后面是items,有个s,表示子项们,是全体;这里是self,单独一个个体。其他区别不大,语法几乎一样:

align-self: auto | flex-start | flex-end | center | baseline | stretch;

唯一区别就是 align-self 多了个 auto (默认值),表示继承自flex容器的 align-items 属性值。其他属性值含义一模一样,如下案例示意:

首先我们设置flex容器 baseline 对齐,然后点击下面的单选框,给第2个flex子项设置不同 align-self 属性值,观察其表现:

.container {
    display: flex;
    align-items: baseline;
    height: 240px;
}
x
RJ3yAn.jpg!web
7nMvIjN.jpg!web

四、其他Flex知识点

  • 在Flex布局中,flex子元素的设置 floatclear 以及 vertical-align 属性都是没有用的。
  • Flexbox布局最适合应用程序的组件和小规模布局,而Grid布局则适用于更大规模的布局。
  • 已经8102年了,Flex老语法不用在管了,舒爽弃之,然后私有前缀也不用再加了,看到就烦。

本教程优点在于交互效果可以实时体验,更直观。如果是转载文章,必定没有效果,访问原文即可。

说实话,自己之前Flex布局用得很少,本文内容自己也是边学边写,文中若有表述不准确的地方欢迎指正。

感谢阅读!

IzmQRff.png!web

参考文章: A Complete Guide to Flexbox


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK