在过去,CSS常用的布局方式分为下面这三种:常规流、浮动、定位。直到弹性盒布局出来之前,浮动是所有网页布局的基础,其依赖于clear属性去解决高度坍塌问题。但浮动最初并不是为了布局而生的,其初衷是为了做文字环绕效果的,用来布局实属无奈,那时别无他选。
但弹性盒布局以及在其之后的网格布局出现后,网页布局有了全新的思路,它们不仅带来了更高的开发效率,能轻松的解决一些特殊布局的问题(例如垂直居中),还能适应新时代响应式的需求。当然,它们在对老版本浏览器的兼容性上不如浮动,一些对兼容性要求很高的大厂比如网易、淘宝他们PC端的网站还在使用浮动,因为它们不得不考虑用户可能还在使用老版本IE的可能性。但目前大多数的浏览器都已经支持弹性盒,如果不是对兼容性要求极高的项目,大可放心使用。
那么今天我们来学习一下弹性盒布局。
接下来我要用一个有趣的情景来帮助你理解弹性盒的各种概念。
假设你现在是一个米其林五星大厨,正在设计一道美味的菜肴,没错,就是人见人爱的烤串!实际上,使用弹性盒布局就有点像在串烤串,写一个完整的弹性盒的过程和将烤串串好并摆在盘子里这个过程有些类似。
首先你要理解一些弹性盒的基本概念。
弹性盒布局的基本概念
p1
1. 容器与元素
当我们把一个容器的display属性值改为 flex 或者 inline-flex,容器就会变成 弹性容器。完成这一步之后,容器中的直系子元素就会变为 弹性项目。在弹性容器中设置的属性我们称为容器属性,在弹性项目中设置的属性我们称为项目属性。
2. 主轴与侧轴
弹性盒布局是一种一维布局,一个弹性盒一次只能处理一个维度上的元素布局,要么一行,要么一列。弹性容器中的元素沿着主轴方向排列,就像一根隐形的签子,串起了所有的元素。而侧轴与主轴垂直,用于控制每个元素在垂直于主轴方向上的位置,为了让肉块在签子上更牢固会选择穿过肉块的中心,而像韭菜则需要穿过韭菜的头部。
好了,最基本的概念就这些。接下来开始做烤串吧!
改变主轴的方向:第一步,签子在盘子中怎么摆放?(flex-direction, flex-wrap, flex-flow)
首先,我们要想象我们最终的成品大概是什么样子。有一个精美的盘子,盘子可以是不同的大小。盘子中放置着一根烤串,烤串上是形状不一,大小不同,烤的滋滋冒油的食材。那么问题来了,这根烤串我是横着摆呢?还是竖着摆呢? 如果有个新疆超大羊肉串,签子远比盘子要长,盘子装不下,怎么处理?
要解决烤串横着摆还是竖着摆的问题,我们需要的属性是:
flex-direction。它控制了主轴的方向,也就是签子的方向。它是容器属性,可选的值为 row | row-reverse | column | column-reverse,不设置的话默认为row。
p2
如果烤串比盘子还要长,这时候就要考虑是否要换行,可以理解为把签子剪断摆成多行。如果要换行,怎么剪呢?沿着签子一直到超出盘子的位置开始剪,多出来的部份在下一行继续沿着主轴摆放,若是还超出盘子就继续剪,直到能装下所有的烤串为止。如果不换行,那么为了把烤串放进盘子中,就会自动压缩每个食材的宽度,这也是弹性盒名字的由来。控制换行与否的属性是
flex-wrap。它是容器属性,可选的值为 wrap | nowrap | wrap-reverse,不设置的话默认no-wrap;
接下来介绍一个简写属性,flex-flow,他可以将flex-direction和flex-wrap组合在一个属性中书写。第一个指定的值是flex-direction,第二个指定的值是flex-wrap。例如,flex-flow: row wrap;
主轴与侧轴的对齐方式:第二步,签子怎么串食材?(justify-content, align-items, align-content)
签子在盘子中的摆放位置确定了,接下来就要开始串食材了,是把食材全部挤在签子的头部或尾部?或者把食材均匀串在签子上?有的食材应该串在食材的正中心,有的食材应该串在食材的头部或者尾部。这些都需要被明确才能让最后的成品符合你的想法。
元素在主轴的分布规则,即食材在签子上的分布规则由justify-content控制,它是容器属性,可选的值有 flex-start | flex-end | center | space-between | space-around | space-evenly。你可以把食材一股脑地挤在签子的头部,也可以让食材均匀分布,这样看起来好看些。
p3
元素在侧轴的分布规则,即签子串在食材的哪个位置有
align-items属性决定,它是容器属性,可选的值有 flex-start | flex-end | center | stretch。如果是肉串一般会串在肉块的中心位置,韭菜串可能会串在韭菜的头部。
p4
align-content则只适用于flex-wrap: wrap的情况,用于调整烤串摆成多行后整体在盘子中的位置,它是容器属性,flex-start | flex-end | center | stretch |space-between | space-around。
还有个align-self属性,它是项目属性,用于给某个特定的元素单独设置以覆盖其父元素的align-items属性,默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同与stretch。
弹性项目的伸缩:第三步,怎么选取食材的大小?(flex-grow, flex-shink, flex-basis, flex)
到这里,一个烤串的基本框架就搭建好了,但是还有个问题其实没有解决,就是食材要选取多大的呢?是当一个良心商家,只要盘子够大,我就选最大的肉块,让烤串刚刚好把盘子塞满,还是规规矩矩控制好肉块的大小,即便盘子再大也不改变肉块的大小。如果盘子太小了,是否要根据食材的不同按不同比例缩小选取食材的大小呢?
为了更好地控制食材的大小,也就是弹性盒的元素,有三个属性可以作用于它们:
- flex-grow
- flex-shrink
- flex-basis
为了书写的方便,我们一般直接使用速写属性flex: (flex-grow) (flex-shrink) (flex-basis),例如 flex: 0 0 100px;
flex-grow
flex-grow定义了元素的放大比例。首先,每个元素都有个初始宽度,一般用flex-basis设置。若容器再容纳了所有元素后仍有剩余空间,就按flex-grow的值来分配剩余空间。
flex-grow默认为0,即如果存在剩余空间也不放大,以flex-basis为宽度。
当flex-grow不为0的时候,这个元素的宽度就不由初始宽度控制,而是由剩余空间按比例分配。
p5
flex-shrink
flex-shrink定义了元素的缩小比例。当容器发现容器的宽度不足以容纳了所有元素,所有的元素宽度需要按不足的宽度以flex-shrink的比例缩小。
默认为1,即如果空间不足,所有元素宽度等比例缩小。
如果设置为0,则空间不足时不缩小。
p6
flex-basisflex-basis指定了弹性盒的元素在主轴方向上的初始宽度。和width有一定关系,两者同时使用,flex-basis优先级更高。如果flex-basis没有设置,flex-basis = width,如果width也没有设置,flex-basis等于内容的宽度。
注意! - 单独使用width,正常使用
- 如果单独使用flex-basis,超过会自动变大不会限制,相当于flex-basis是最小宽度
- 如果同时使用,实际宽度为限制flex-basis和width两者的最大者,并且会限制,内容超出直接溢出(不使用break-all)
- 如果有max-width和min-width,flex-basis受到这两个属性的限制
好了,到这里你就学会了弹性盒的基本使用方法了,快去试试吧!