Flex入坑指南

弹性布局flex是一个几年前的CSS属性了,说它解放了一部分生产力不为过。至少解放了很多CSS布局相关的面试题 :)
以前网上流行的各类XX布局,什么postion: absolute+marginfloat+padding,各类均可以使用flex来取代之。
早两年在使用的时候,仍是会担忧有兼容性问题的,某些手机在使用了auto-prefixer之后依然会出现不兼容的问题。
好在如今已是2018年了,没必要再担忧那些老旧的设备,但愿这篇文章能帮你加深对flex的认识。css

准备工做

首先,flex被称为一个弹性盒模型,也有称弹性布局的。
总之,盒子也好、布局也罢,咱们老是须要有一个容器Container的:html

<div class="container"></div>

以及若是单纯的只是一个容器的话,是没有任何意义的。
因此咱们还须要有一些内容:git

<div class="contianer">
  <div class="item"></div>
  <div class="item"></div>
</div>

下边的全部例子基本都是基于以上DOM结构来作的。github

基本语法

如今咱们已经有一个能够用来写flex布局的html结构。
接下来就是一个最基础的flex布局的实现:面试

<style>
  .container {
    display: flex;
    height: 50px;

    color: #fff;
    border: 1px solid #03a9f4;
  }

  .item {
    flex: 1;

    text-align: center;
    background: #03a9f4;
  }
</style>
<div class="contianer">
  <div class="item"></div>
  <div class="item"></div>
</div>

咱们在容器上使用display: flex来告诉浏览器,这是一个flex布局的开始。
而后给全部的item添加一个flex: 1的属性,来代表,咱们这里边全部的子元素会沿着主轴平分全部的区域,就这样,咱们已经实现了一个多列等宽布局。 浏览器

关于flex,最重要的就是要记住他有两条轴线(主轴、交叉轴),绝大部分属性都是依赖于轴线的方向。
ide

图片来自 MDN

由于flex布局分为了容器和内容两块,各自有各自的属性,因此就先从容器类的提及。布局

容器相关的flex属性

实现上边的需求,是依赖于不少默认属性值。
好比,为何咱们的子元素会横向的进行分割空间,而不是竖向的,这里就用到了一个属性的默认值:post

flex-direction

flex-direction用于定义flex布局中的主轴方向。
默认取值为row,是横向的,表示从左到右,也就是说咱们的全部子元素会按照从左到右的顺序进行排列。
咱们能够经过设置值为column来改变主轴的方向,将其修改成从上到下。(改变flex-direction的值会影响到一些相关的属性,会在下边说到) flex

flex-direction共有四个有效值可选:

  1. row 默认值,从左到右
  2. row-reverse 从右到左
  3. column 从上到下
  4. column-reverse 从下到上

P.S. 在React-Native中默认的主轴方向为column

因此说flex-direction的做用就是:定义容器中元素的排列方向

flex-wrap

该属性用于定义当子元素沿着主轴超出容器范围后,应该按照怎样的规则进行排列。
该属性只有简单的三个取值:

  1. wrap 超出主轴范围后换行显示,换行方向按照交叉轴的方向来(默认状况下就是折行到下一行
  2. wrap-reverse 超出主轴范围后换行显示,可是方向是交叉轴的反向(也就是默认状况下第一行会出如今最下边
  3. nowrap 即便超出容器也不会进行换行,而是尝试压缩内部flex元素的宽度(在下边的子元素相关的属性会讲到

三种取值的示例:
g0no.png

flex-flow

flex-flow是一个简写的属性,适用于上边提到的flex-directionflex-wrap

语法:

selector {
  flex-flow: <flex-direction> <flex-wrap>;
}

justify-content

这个会定义咱们的子元素如何沿着主轴进行排列,由于咱们上边是直接填充满了父元素,不太能看出效果。
因此咱们对代码进行以下修改:

<style media="screen">
  .container {
    display: flex;
    width: 400px;

    color: #fff;
    border: 1px solid #03a9f4;
  }

  .item {
    /* flex: 1; */
    width: 100px;

    text-align: center;
    background: #03a9f4;
  }
</style>
<div class="container">
  <div class="item">Item 1</div>
  <div class="item">Item 2</div>
  <div class="item">Item 3</div>
</div>

将全部的子元素都改成固定的宽度,也就是说,若是父元素有剩余空间的话,就会空在那里。
justify-content的默认取值为normal,也能够认为就是start了,也就是根据主轴的方向(flex-direction)堆在起始处。

几个经常使用的取值:

  1. center 必然首选的是center,可以完美的实现沿主轴居中
  2. flex-start 沿着主轴从行首开始排列
  3. flex-end 沿着主轴从行末开始排列

以及几个不太经常使用的取值:

  1. space-between 将剩余空间在子元素中间进行平分,保证沿主轴两侧不会留有空白。
  2. space-around 将剩余空间均匀的分布在全部的子元素沿主轴方向的两侧,也就是说,主轴两侧也会有空白,可是必然是中间空白的1/2大小。
  3. space-evenly 将剩余空间在全部元素之间平均分配,主轴两侧的空白面积也会与中间的面积相等。

六种效果的示例:
6dn.png

Warning

有一点须要注意,justify-content的取值都是依照flex-direction所定义的主轴方向来展现的。
也就是说,center在默认状况下用于水平居中,在flex-direction: column-*时,则是做为垂直居中来展现的。

align-content

一样的,align-content也是用来控制元素在交叉轴上的排列顺序,可是既然会出现两个属性(align-itemsalign-content),势必二者之间会有一些区别。

由于align-content只能做用于多行状况下的flex布局,因此取值会更接近额旋转后的justify-content,一样的可使用space-between之类的属性值。

由于取值基本相似,因此再也不重复上边justify-content所列的表格,直接上效果:
bafa.png

align-items

align-items与上边的justify-content相似,也适用于定义子元素的排列方式。
不一样的是,align-items做用于交叉轴(也就是默认flex-direction: row状况下的从上到下的那根轴线)
目测平时用到的最多的地方就是水平居中吧(我如今懒的:只要有图标、表单 & 文字 的单行混合,都会选择align-items: center来实现:)

经常使用的取值:

  1. center 经常使用来作垂直(交叉轴)居中
  2. flex-start 沿着交叉轴的起始位置排列
  3. flex-endflex-start方向相反
  4. stretch 将元素撑满容器的交叉轴宽度(在默认状况下,这里指容器的高度,可是若是单纯的说这条轴线,我以为宽度更合适一些
  5. baseline 将元素按照文本内容的基线进行排列

以上取值的示例:
l6ri.png

align-content与align-items的异同

二者的相同点在于,都是设置元素在交叉轴上的排列顺序。
而区别在于如下两点:

  1. align-content只能应用于多行的状况下
  2. align-content会将全部的元素认为是一个总体并进行相应的处理、而align-items则会按照每一行进行处理:

cvld.png

place-content

place-content能够认为是justify-contentalign-content的简写了(事实上就是

语法为:

selector {
  place-content: <align-content> <justify-content>;
}

P.S. 若是单行(元素)想要实现居中仍是老老实实的使用align-items+justify-content吧 :)

子元素的属性们

有关容器的全部属性都已经列在了上边,下边的一些则是在容器内元素设置的属性。

flex-grow

flex-grow用来控制某个子元素在须要沿主轴填充时所占的比例,取值为正数(浮点数也能够的)。

selector {
  flex-grow: 1;
  flex-grow: 1.5;
}

举例说明:
若是一个容器中有三个元素,容器剩余宽度为100px,三个元素须要进行填充它。
若是其中一个元素设置了flex-grow: 2,而其余的设置为1(默认不设置的话,不会去填充剩余宽度)
则会出现这么一个状况,第一个元素占用50px,而其余两个元素各占用25px

tcd0.png

Warning

这里须要注意的一点是,flex-grow定义的是对于剩余宽度的利用。
元素自身占用的空间不被计算在内,为了验证上边的观点,咱们进行一个小实验。
给每个元素设置一个padding-left: 20px,保证元素自身占用20px的位置,而后分别设置flex-grow来查看最后元素的宽度是多少。

.container {
  display: flex;
  width: 160px;
  height: 20px;
  align-items: stretch;
}

.item {
  flex-grow: 1;
  padding-left: 20px;
}

.item:first-of-type {
  flex-grow: 2;
}

4fc7.png
3jm1.png

咱们给容器设置了宽度为160px(为了方便的减去padding-left计算)。
最后获得的结果,设置了flex-grow: 2的元素宽度为70px,而设置flex-grow: 1的元素宽度为45px
在减去了自身的20px之后,50 / 25 === 2 // true

flex-shrink

flex-shrink能够认为是与flex-grow相反的一个设置,取值一样是正数。
用来设置当容器宽度小于全部子元素所占用宽度时的缩放比例。
好比说,若是咱们的容器宽为100px,三个元素均为40px,则会出现容器没法彻底展现全部子元素的问题。
因此默认的flex会对子元素进行缩放,各个元素要缩放多少,则是根据flex-shrink的配置来获得的(默认为1,全部元素平均分摊
就像上边的例子,若是咱们仍是三个元素,第一个设置了flex-shrink: 2,则最终获得的结果,第一个元素宽度为30px,其他两个元素的宽度为35px

.container {
  display: flex;
  width: 100px;
  height: 20px;
  align-items: stretch;
}

.item {
  width: 40px;
  /* flex-shrink: 1; it's default value */
  font-size: 0;
  background: #03a9f4;
}

.item:first-of-type {
  flex-shrink: 2;
}

1s06.png
8rro.png

flex-basis

这个属性用来设置元素在flex容器中所占据的宽度(默认主轴方向),这个属性主要是用来让flex来计算容器是否还有剩余面积的。
默认取值为auto,则意味着继承widthdirection: column时是height)的值。
通常来说不多会去设置这个值。

flex

flex则是上边三个属性的简写,语法以下:

selector {
  flex: <flex-grow> <flex-shrink> <flex-basis>;
}

通常来说若是要写简写的话,第三个会选择设置为auto,也就是获取元素的width

align-self

效果如同其名字,针对某一个元素设置相似align-items的效果。
取值与align-items一致,好比咱们能够针对性的实现这样的效果:

.center :first-child {
  align-self: stretch;
}

.flex-start :first-child {
  align-self: flex-end;
}

.flex-end :first-child {
  align-self: flex-start;
}

.stretch :first-child {
  align-self: center;
}

83evalign-self-example-1

order

以及最后这里还有一个order属性,能够设置在展现上的元素顺序。
取值为一个任意整数。

默认的取值为1,若是咱们想要后边的元素提早显示,能够设置以下属性:

.item:last-of-type {
  order: -1;
}

92r4.png

P.S. 这个顺序的改变只是显示上的,不会真正的改变html的结构,好比,你依然不能经过.item:last-of-type ~ .item来获取它在视觉上后边的兄弟元素
当order重复时,按照以前的顺序排列大小

总结

flex相关的属性如何拆分之后,并不算太多。
脑海中有主轴和交叉轴的概念以后,应该会变得清晰一些。
关于上述全部属性的一个简单总结:

容器相关

属性名 做用
flex-direction 用来设置主轴的方向,最基础的属性,默认从左到右,此属性一改,下列全部的属性都要跟着改,真可谓牵一发而动全身
flex-wrap 设置元素超出容器后的换行规则,默认不换行
justify-content 设置沿主轴的排列规则
align-content 设置沿交叉轴的排列规则
align-items 以行(默认direction状况下)为单位,设置沿交叉轴的排列规则

元素相关

属性名 做用
flex-grow 当容器大于全部元素时,按什么比例将剩余空间分配给元素
flex-shrink 当容器小于全部元素时,元素按照什么比例来缩小本身
flex-basis 不多用的属性,设置在容器中的宽(高)
align-self 针对某些元素单独设置align-items相关的效果
order 设置元素在显示上的顺序

简写

属性名 做用
flex-flow flex-directionflex-wrap的简写
place-content justify-contentalign-content的简写
flex flex-growflex-shrinkflex-basis的简写

以及文中全部的示例代码都在这里 code here

参考资料

  1. How Flexbox works (此文中的一些gif图真心赞)
  2. Understanding Flexbox: Everything you need to know
  3. Learn CSS Flexbox in 5 Minutes

P.S. 先立一个flag,后续还会出一篇各类flex的真实场景应用,毕竟,纸上谈兵没有意义

相关文章
相关标签/搜索