内容简介:目前在不考虑IE以及低端安卓机(4.3-)的兼容下,已经可以放心使用flex进行布局了。什么是flex布局以及它的好处,这里就不再赘述。在这篇文章里,想说说flex布局的属性语法及其细节。那么网上也有不少flex布局的教程,为什么又要再写一篇?首先,flex布局的迷之属性们,如果一知半解,机械记忆的话,那不到半个月基本忘光光。先感受一下这12个flex布局属性,是不是很“迷”人。
零、前言
目前在不考虑IE以及低端安卓机(4.3-)的兼容下,已经可以放心使用flex进行布局了。什么是flex布局以及它的好处,这里就不再赘述。
在这篇文章里,想说说flex布局的属性语法及其细节。那么网上也有不少flex布局的教程,为什么又要再写一篇?
首先,flex布局的迷之属性们,如果一知半解,机械记忆的话,那不到半个月基本忘光光。先感受一下这12个flex布局属性,是不是很“迷”人。
容器属性
- flex-flow
- flex-direction
- flex-wrap
- justify-content
- align-items
- align-content
元素属性
- order
- flex-grow
- flex-shrink
- flex-basis
- flex
- align-self
就连老外也都在twitter吐槽不好理解,可见还是有一定的学习成本。
而目前很多flex教程主要以列举属性为主,缺乏对比和理解性脉络。
因此,下面会通过我梳理的一个脉络去理解flex布局,包括不同属性的异同以及一些容易造成误解的细节点,彻底弄懂flex布局。
一、flex弹性盒模型
对于某个元素只要声明了 display: flex;
,那么这个元素就成为了弹性容器,具有flex弹性布局的特性。
- 每个弹性容器都有两根轴: 主轴和交叉轴 ,两轴之间成90度关系。注意: 水平的不一定就是主轴。
- 每根轴都有 起点和终点 ,这对于元素的对齐非常重要。
- 弹性容器中的所有子元素称为<弹性元素>, 弹性元素永远沿主轴排列 。
-
弹性元素也可以通过
display:flex
设置为另一个弹性容器,形成嵌套关系。因此 一个元素既可以是弹性容器也可以是弹性元素 。
弹性容器的两根轴非常重要,所有属性都是作用于轴的。下面从轴入手,将所有flex布局属性串起来理解。
二、主轴
flex布局是一种 一维布局 模型,一次只能处理一个维度(一行或者一列)上的元素布局,作为对比的是二维布局 CSS Grid Layout ,可以同时处理行和列上的布局。
也就是说, flex布局大部分的属性都是作用于主轴的,在交叉轴上很多时候只能被动地变化 。
1. 主轴的方向
我们可以在弹性容器上通过 flex-direction
修改主轴的方向。如果主轴方向修改了,那么:
- 交叉轴就会相应地旋转90度。
- 弹性元素的排列方式也会发生改变,因为 弹性元素永远沿主轴排列 。
2. 沿主轴的排列处理
弹性元素永远沿主轴排列,那么如果主轴排不下,该如何处理?
通过设置 flex-wrap: nowrap | wrap | wrap-reverse
可使得主轴上的元素不折行、折行、反向折行。
默认是 nowrap
不折行,难道任由元素直接溢出容器吗?当然不会,那么这里就涉及到元素的弹性伸缩应对,下面会讲到。
wrap
折行,顾名思义就是另起一行,那么折行之后行与行之间的间距(对齐)怎样调整?这里又涉及到交叉轴上的多行对齐。
wrap-reverse
反向折行,是从容器底部开始的折行,但每行元素之间的排列仍保留正向。
3. 一个复合属性
flex-flow = flex-drection + flex-wrap
flex-flow
相当于规定了flex布局的“工作流(flow)”
flex-flow: row nowrap;
三、元素如何弹性伸缩应对
当 flex-wrap: nowrap;
不折行时,容器宽度有剩余/不够分,弹性元素们该怎么“弹性”地伸缩应对?
这里针对上面两种场景,引入两个属性(需应用在弹性元素上)
flex-shrink flex-grow
1. flex-shrink: 缩小比例
来看下以下场景,弹性容器 #container
宽度是200px,一共有三个弹性元素,宽度分别是50px、100px、120px。在不折行的情况下,此时容器宽度是明显不够分配的。
实际上, flex-shrink
默认为1,也就是当不够分配时,元素都将等比例缩小,占满整个宽度,如下图。
#container { display: flex; flex-wrap: nowrap; }
元素收缩的计算方法
真的是等比缩小(每个元素各减去70/3的宽度)吗?这里稍微深究一下它的收缩计算方法。
- 弹性元素1:50px→37.03px
- 弹性元素2:100px→74.08px
- 弹性元素3:120px→88.89px
先抛结论: flex-shrink: 1
并非严格等比缩小, 它还会考虑弹性元素本身的大小
。
-70px 1*50 + 1*100 + 1*120 = 270 1*50/270 1*50/270 * (-70) 50px + (1*50/270 *(-70)) = 37.03px
加入弹性元素本身大小作为计算方法的考虑因素,主要是为了避免将一些本身宽度较小的元素在收缩之后宽度变为0的情况出现。
2. flex-grow: 放大比例
同样,弹性容器 #container
宽度是200px,但此时只有两个弹性元素,宽度分别是50px、100px。此时容器宽度是有剩余的。
那么剩余的宽度该怎样分配?而 flex-grow
则决定了要不要分配以及各个分配多少。
(1)在flex布局中,容器剩余宽度默认是不进行分配的,也就是所有弹性元素的 flex-grow
都为0。
(2)通过指定 flex-grow
为大于零的值,实现容器剩余宽度的分配比例设置。
元素放大的计算方法
放大的计算方法并没有与缩小一样,将元素大小纳入考虑。
仅仅按 flex-grow
声明的份数算出每个需分配多少,叠加到原来的尺寸上。
50px 50px / (3+2) = 10px 50px + 3 * 10 = 80px
无多余宽度时,flex-grow无效
下图中,弹性容器的宽度正好等于元素宽度总和,无多余宽度,此时无论 flex-grow
是什么值都不会生效。
同理,对于 flex-shrink
,在容器宽度有剩余时也是不会生效的。因此这两个属性是针对两种不同场景的互斥属性。
四、弹性处理与刚性尺寸
在进行弹性处理之余,其实有些场景我们更希望元素尺寸固定,不需要进行弹性调整。设置元素尺寸除了width和height以外,flex还提供了一个 flex-basis
属性。
flex-basis
设置的是元素在主轴上的初始尺寸,所谓的初始尺寸就是元素在 flex-grow
和 flex-shrink
生效前的尺寸。
1. 与width/height的区别
首先以width为例进行比较。看下下面的例子。 #container {display:flex;}
。
<div id="container"> <div>11111</div> <div>22222</div> </div>
(1) 两者都为0
- width: 0 —— 完全没显示
- flex-basis: 0 —— 根据内容撑开宽度
(2) 两者非0
- width: 非0;
- flex-basis: 非0
—— 数值相同时两者等效
—— 同时设置,flex-basis优先级高
(3) flex-basis为auto
flex-basis为auto时,如设置了width则元素尺寸由width决定;没有设置则由内容决定
(4) flex-basis == 主轴上的尺寸 != width
- 将主轴方向改为:上→下
- 此时主轴上的尺寸是元素的height
- flex-basis == height
2. 常用的复合属性 flex
这个属性应该是最容易迷糊的一个,下面揭开它的真面目。
flex = flex-grow + flex-shrink + flex-basis
复合属性,前面说的三个属性的简写。
一些简写
-
flex: 1
=flex: 1 1 0%
-
flex: 2
=flex: 2 1 0%
-
flex: auto
=flex: 1 1 auto;
-
flex: none
=flex: 0 0 auto;
// 常用于固定尺寸 不伸缩
flex:1 和 flex:auto 的区别
其实可以归结于 flex-basis:0
和 flex-basis:auto
的区别。
flex-basis
是指定初始尺寸,当设置为0时(绝对弹性元素),此时相当于告诉 flex-grow
和 flex-shrink
在伸缩的时候不需要考虑我的尺寸;相反当设置为 auto
时(相对弹性元素),此时则需要在伸缩时将元素尺寸纳入考虑。
因此从下图(转自W3C)可以看到绝对弹性元素如果 flex-grow
值是一样的话,那么他们的尺寸一定是一样的。
五、容器内如何对齐
前面讲完了元素大小关系之后,下面是另外一个重要议题—— 如何对齐 。可以发现上面的所有属性都是围绕主轴进行设置的,但在对齐方面则不得不加入作用于交叉轴上。需要注意的是这些对齐属性都是作用于容器上。
1. 主轴上的对齐方式
justify-content
2. 交叉轴上的对齐方式
主轴上比较好理解,重点是交叉轴上。因为交叉轴上存在单行和多行两种情况。
交叉轴上的单行对齐
align-items
默认值是 stretch
,当元素没有设置具体尺寸时会将容器在交叉轴方向撑满。
当 align-items
不为 stretch
时,此时除了对齐方式会改变之外,元素在交叉轴方向上的尺寸将由内容或自身尺寸(宽高)决定。
注意,交叉轴不一定是从上往下,这点再次强调也不为过。
交叉轴上的多行对齐
还记得可以通过 flex-wrap: wrap
使得元素在一行放不下时进行换行。在这种场景下就会在交叉轴上出现多行,多行情况下,flex布局提供了 align-content
属性设置对齐。
align-content
与 align-items
比较类似,同时也比较容易迷糊。下面会将两者对比着来看它们的异同。
首先明确一点: align-content
只对多行元素有效, 会以多行作为整体进行对齐
,容器必须开启换行。
align-content: stretch | flex-start | flex-end | center | space-between | space-around align-items: stretch | flex-start | flex-end | center | baseline
在属性值上, align-content
比 align-items
多了两个值: space-between
和 space-around
。
align-content与align-items异同对比
与 align-items
一样, align-content:
默认值也是 stretch
。两者同时都为 stretch
时,毫无悬念所有元素都是撑满交叉轴。
#container { align-items: stretch; align-content: stretch; }
当我们将align-items改为 flex-start
或者给弹性元素设置一个具体高度,此时效果是行与行之间形成了间距。
#container { align-items: flex-start; align-content: stretch; } /*或者*/ #container { align-content: stretch; } #container > div { height: 30px; }
为什么?因为 align-content
会以整行为单位,此时会将整行进行拉伸占满交叉轴;而 align-items
设置了高度或者顶对齐,在不能用高度进行拉伸的情况下,选择了用间距。
尝试把 align-content
设置为顶对齐,此时以行为单位,整体高度通过内容撑开。
而 align-items
仅仅管一行,因此在只有第一个元素设置了高度的情况下,第一行的其他元素遵循 align-items: stretch
也被拉伸到了50px。而第二行则保持高度不变。
#container { align-items: stretch; align-content: flex-start; } #container > div:first-child { height: 50px; }
两者的区别还是不明显?来看下面这个例子。
这里仅对第二个元素的高度进行设置,其他元素高度则仍保持内容撑开。
以第一个图为例,会发现 align-content
会将所有行进行顶对齐,然后第一行由于第二个元素设置了较高的高度,因此体现出了底对齐。
两者差异总结:
- 两者“作用域”不同
- align-content管全局(所有行视为整体)
- align-items管单行
能否更灵活地设置交叉轴对齐
除了在容器上设置交叉轴对齐,还可以通过 align-self
单独对某个元素设置交叉轴对齐方式。
-
值与
align-items
相同 -
可覆盖容器的
align-items
属性 -
默认值为
auto
,表示继承父元素的align-items
属性
#container { display: flex; align-items: flex-start; } #container > div:first-child { align-self: stretch; } #container > div:nth-child(3) { align-self: center; } #container > div:nth-child(4) { align-self: flex-end; }
六、其他
order:更优雅地调整元素顺序
#container > div:first-child { order: 2; } #container > div:nth-child(2) { order: 4; } #container > div:nth-child(3) { order: 1; } #container > div:nth-child(4) { order: 3; }
order:可设置元素之间的排列顺序
- 数值越小,越靠前,默认为0
- 值相同时,以dom中元素排列为准
七、总结
附
参考阮老师博文中的骰子练习,我做了张图,大家不妨可以各自实现下,理解之后应该能够比较轻松地写出来。 codepen
参考资料
深入理解css3中的flex-grow、flex-shrink、flex-basis
本文中未标明转载的图均属于原创,引用转载请注明来源。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
信息学奥林匹克教程·提高篇
吴耀斌 / 湖南师范大学出版社 / 2003-1 / 24.00元
《信息学奥林匹克教程》(提高篇)既有各个算法设计基本思路的讲解及对求解问题的分析,注重了算法引导分析与不同算法的比较,又给出了具体的编程思路与参考程序,程序采用信息学竞赛流行的Turbo Pascal7.0语言编写,并注重结构化与可读性。一起来看看 《信息学奥林匹克教程·提高篇》 这本书的介绍吧!