学习 Flex 布局
flex 是 css3 推出的一种布局方式,至今有超过十年时间了
要实现 flex 布局很容易,只需要给一个元素的 display
属性设置为 flex
就行
.box { display: flex; }
咋看之下好像没什么变化,那是因为受到影响的其实是其内部的元素,给这个容器内添加几个元素就可以看到效果
<div class="box"> <div class="item-1">1</div> <div class="item-2">2</div> <div class="item-3">3</div> </div>
可以看到的是默认情况下应该独占一行的 <div>
元素现在全部挤在了一行,这就是 flex 的效果,也就是说只要一行代码就实现了 flex 布局,不愧为大神级理解
flex-direction
简单的说,布局其实就是一个怎么摆放的问题,内部那些元素既然可以摆成一行,当然也可以摆成一列,只需要向容器添加一个 flex-direction
属性,就能改变内部元素的摆放方向
.box { flex-direction: column; }
当其值为 column
的时候即为按列,而之前的默认值是 row
,一旦确定了摆放方向后,则该方向成为 flex 的主轴,用箭头来表示就像这样
flex-direction: row
flex-direction: column
另外还有两个摆放方向,就是这两者相反的方向
flex-direction: column-reverse
flex-direction: column-reverse
justify-content
有了方向之后,就有了起点和终点,前面这些元素都是挤在主轴的起点位置,我们可以通过添加一个 justify-content
属性改变这些元素在主轴上的位置
.box { justify-content: flex-end; }
这样就全部跑到主轴的终点位置去了
justify-content: flex-end
也能摆在中间
justify-content: center
理所当然的默认值就应该是起点了 flex-start
,除了这种一锅端式的对齐方式外,还能让这些元素均匀地分布于主轴上,有3种方式
1种是两端不留空,两端的元素和容器之间无间隔
justify-content: space-between
1种是两端留空,两端的元素和容器之间也有同等的间隔
justify-content: space-evenly
还有1种是每个元素两边留相等的间距,这种情况下两端的元素和容器之间的距离是元素之间距离的一半
justify-content: space-around
align-items
另外和主轴垂直的一个方向称为交叉轴,不同于主轴,元素也可以在交叉轴上挪动位置,只需要给容器添加一个 align-items
属性
.box { align-items: stretch; }
这是默认值,也就是说默认情况下元素在交叉轴上是拉伸的
align-items: stretch
此外还有3种普通对齐方式,即起点(flex-start),终点(flex-end)和居中(center)
align-items: flex-start|center|flex-end
另外还有一个值是 baseline
,这是根据文字的基线对齐,改变每一项文字的大小可以看出效果
align-items: baseline
在主轴上对齐使用 justify-content
,在交叉轴上对齐使用 align-items
,这个一定要记清,因为它喵的还有个 align-content
属性!
flex-wrap
前面在容器中一直都只有3个元素,假如我们给添加到30个会怎样?
会傻傻地挤在一堆,哪怕容器已经放不下了,因为默认是不会自动换行的,需要给容器添加一个 flex-wrap
属性
.box { flex-wrap: wrap; }
flex-wrap: wrap
除了这种理所当然的换行方式外,还有一种意想不到的反方向换行方式
flex-wrap: wrap-reverse
为什么会有这么一种奇葩的换行方式呢,因为前面 flex 的主轴由 flex-direction
属性定义,总共有4个方向,而交叉轴是垂直于主轴的,但其方向是固定的,如果主轴横向的话,无论向左还是向右,交叉轴都是自上而下;而如果主轴是纵向的话,那么交叉轴就是从左至右。但是这个 flex-wrap: wrap-reverse
属性设置之后就会改变交叉轴的方向,原本的起点和终点的位置就交换了
align-items: flex-start; flex-wrap: wrap-reverse
可以看到,交叉轴的起点跑到容器下沿去了,说明这时候交叉轴是自下而上的。不过如果经常使用的是居中对齐或者均匀分布的话根本不用关心什么起点终点的
align-content
说到均匀分布,前面只提到可以在主轴上均匀分布,但当参与布局的元素多到已经一行或是一列装不下的时候,在交叉轴上也是可以均匀分布的,这就需要前面提到的 align-content
属性,其值和 justify-content
一样,这两个属性才是对应的,同样有3种均匀分布方式
align-content: space-between|space-evenly|space-around
以及起点,终点和居中对齐等等
align-content: flex-start|flex-end|center
其默认值是 stretch
order
一直以来容器里的元素都是按顺序摆放的,那么可不可以*调整元素的摆放顺序呢,比如将第2个元素摆到最前面呢,当然,只需要添加一个 order
属性即可,需要注意的是前面添加的所有属性都是针对容器内的所有元素的,因而那些属性都是设置在容器上的,而这时只是想改变第2个元素的顺序,因此 order
属性需要添加到对应的元素上
.item-2 { order: -1; }
因为 order
的默认值是 0,只需要给个比 0 小的值就可以摆到前面,同理,给个比 0 大的值就可以摆到末尾去,给每个元素设置一个不一样的 order
的值就会按照从小到大的顺序依次摆放
align-self
既然可以单独改变某个元素的顺序,那么是不是也可以单独改变某个元素的对齐方式呢,让这个元素不跟着大部队一起走,特立独行一点,这当然是可以的,需要用到 align-self
属性,它的值和 align-items
基本一样,同样是 align-
前缀,那就意味着是在交叉轴上使用自己的对齐方式
.item-2 { align-self: flex-end; }
align-self: flex-end
那么在主轴上能不能使用特立独行的对齐方式呢,比如有没有一个 justify-self
属性,目前来看好像貌似不得行。
flex
虽然在交叉轴上元素会默认拉伸,但是在主轴上当元素比较少的时候会留有很多空间,这时候就要祭出可能是 flex 的最后一个属性了,那就是 flex
,给每个元素都添加一个值为 1 的 flex
属性
.item { flex: 1; }
这样所有元素就会平分容器的空间
而给每个元素设置不同的值,则会按比例分配空间
.item-1 { flex: 2; } .item-2 { flex: 1; } .item-3 { flex: 3; }
由于 2 + 1 + 3 = 6,根据比例第 1 项分得 1/3,第 2 项得到 1/6,第 3 项得到一半
这个数值越大,分得越多,默认值是 0,那就相当于是净身出户,一点都不要了,当只给一个元素设置值为 1 的时候,这个元素就会独享主轴上的剩余空间,当值小于 1 的时候会按这个小数的比例来分配
flex
属性还有第 2 个值,第 2 个值和第 1 个值刚好相反,第 1 个值规定容器空间太多的时候每个元素怎么分,第 2 个值则是规定当元素空间不足以容纳这所有元素的时候,每个元素应该如何缩小来腾出足够的空间,其默认值是 1,表示默认情况下所有元素都会自行缩小,这个数值越大,表示责任就越大,需要为腾出空间出更多力,为 0 则表示这是只铁公鸡一毛不拔,只能让其它不为 0 的元素来缩小以腾出空间
.item { flex: 0 1; }
flex
属性还有第三个值,规定某个元素在主轴上占据的空间,默认值是 auto
,表示元素占据的空间由其自身决定,其值可以是各种长度单位
.item { flex: 0 1 60px; }
由此 flex
的完整默认值就是 0 1 auto
,这是个简写属性,由 flex-grow
,flex-shrink
和 flex-basis
这 3 个属性组成,如果只想单独设置其中某个值的时候可以用到
.item { flex-grow: 0; flex-shrink: 1; flex-basis: 60px; }