深入理解 flex 布局以及计算_Flexbox, Layout
Posted Leaves丶幻
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解 flex 布局以及计算_Flexbox, Layout相关的知识,希望对你有一定的参考价值。
起因
对于Flex布局,阅读了 大漠老师和其他老师写的文章后,我还是不太理解Flexbox是如何弹性的计算子级项目的大小以及一些其他细节。在大漠老师的帮助下,我去查阅Flexbox 的 W3C 规范文档。
注:本篇博文不适合未接触过Flex 布局的人, 如果想了解flex 布局基础。请参考理解Flexbox:你需要知道的一切
对于flex盒模型的设计期望
flex盒模型是被期望设计成:
- 在任何流动的方向上(包括上下左右)都能进行良好的布局
- 可以以逆序 或者 以任意顺序排列布局
- 可以线性的沿着主轴一字排开 或者 沿着侧轴换行排列
- 可以弹性的在任意的容器中伸缩大小(今天重点研究的主题)
- 可以使子元素们在容器主轴方向上 或者 在容器侧轴方向上 进行对齐
- 可以动态的 沿着主轴方向 伸缩子级的尺寸,与此同时保证父级侧轴方向上的尺寸
主轴和侧轴
很有必要先向大家解释清楚 3个问题
- 什么是主轴
- 什么是侧轴
- 他们是如何切换的
首先每一根轴都包括 三个东西:维度、方向、尺寸
什么意思呢?
- 所谓的维度实际上就是意思就是子元素 横着排还是竖着排(
x
轴 或y
轴) - 方向 即排列子元素的顺序 顺序还是逆序
- 尺寸 即
width
[height
] : 每一个子元素在主轴方向所占的位置的总和 如果主轴是水平的,那么尺寸就是父元素内所有item
的outerWidth
总和,如果主轴是垂直的,那么尺寸就是父元素的outerHeight
主轴是依靠 flex-direction
和 所有子元素在主轴方向上的item-size
的总和确定的,flex-direction
这个属性可以控制子元素的排列方向和排列顺序。
侧轴是依靠 flex-wrap
和 所有子元素在主轴方向上的item-size
的总和确定的,flex-wrap
可以控制子元素 在侧轴方向上的排列方式以及顺序。
而关于不同种类不同情况下的 item-size
我们会在下面讨论,现在您可以简单将它理解为width
[height
]。
盗规范中的一张图
为了方便 flex-direction + flex-wrap
合并成了一个属性 flex-flow
通过这个简单而复杂的属性,我们就能够控制所有子元素的水平和垂直方向,逆序排列和顺序,换行和不换行。
主侧轴的切换十分简单,当主轴设定的时候,它的垂直面,就默认被设定成了侧轴。如:
flex-flow: row-reverse wrap-reverse;
这条CSS属性能够告诉我们那些信息?
- 子元素是横着排列的,主轴是水平的横轴,侧轴是竖直的纵轴
- 子元素是逆序并沿着主轴排列的,从右到左
- 子元素是换行的
- 子元素是逆序并沿着侧轴排列的,从下到上
FFC (flex formatting context)
Flexbox 布局新定义了格式化上下文,类似 BFC(block formatting context)。有多类似呢? 就是除了布局和一些细节不同以外的一切规则都和 BFC 是相同的
。
注意 : 我所指的Flexbox 是指设置了
display: flex;
或display: inline-flex;
的盒子。不是指单单设置了display: flex;
的盒子。
例如,设置了 display: flex;
或 display: inline-flex
的元素,和BFC一样,不会被浮动的元素遮盖,不会垂直外边距坍塌等等。
而对于设置了 display: inline-flex
的盒子来说,我们可以类比 display: inline-box;
行理解。即 一个被行列化后的 Flexbox。它不会独占一行,但是可以设置宽和高。
与BFC的细微区别
但需要注意的是以下几点细节,Flexbox 布局 和 Block 布局是有细微区别的
- Flexbox 不支持
::first-line
和::first-letter
这两种伪元素 vertical-align
对 Flexbox 中的子元素 是没有效果的float
和clear
属性对 Flexbox 中的子元素是没有效果的,也不会使子元素脱离文档流(但是对Flexbox 是有效果的!)- 多栏布局
(column-*)
在 Flexbox 中也是失效的,就是说我们不能使用多栏布局在Flexbox 排列其下的子元素(鱼和熊掌不可得兼嘛) - Flexbox 下的子元素不会继承父级容器的宽
flex item(flex 子元素)
CSS解析器会把 定义了 display: flex;
和 display: inline-flex;
的 Flexbox 下的子元素外部装进一个看不见的盒子里,我们通过排列这些盒子来达到排序、布局、 伸缩的目的。
规范中把这种盒子 称为 flex item
,而子元素中包括了 标签节点 以及 文本节点。标签节点很容易理解,需要注意的是文本节点。
默认情况下,flex
会将 连续的文本节点 装进 flex-item 之中,使文本可以和标签节点一起排序和定位。
值得注意的是,空格也是文本节点,所以 white-space
会影响Flexbox 中的布局:
设置了white-space: pre
的Flexbox
flex-item-size 如何计算的
item-size
(尺寸)为主轴方向上item
的 content
再加上自身的margin
、 border
和 padding
就是这个 item
的尺寸。
在规范中 介绍了 flex-item content 的计算方式
分为以下这几种情况
1. flex-basis 的优先级比 width[height]: 非auto; 高
如果子元素没有内容和默认固定宽高,且设置了flex-basis
。flex-item content
以flex-basis
来决定,无论width[height]
设置了多少。
(可理解为 flex-basis
比 width[height]: 非auto;
的优先级高)
flex-basis
的优先级比width[height]
高,无论width[height]
设置多少,flex-item content都以flex-basis
来决定。
2.元素存在默认宽高
如果子元素有默认固定宽高(例如input
标签)、并且设置了 flex-basis
,那么它的 content
以 固定宽高为下限,如果flex-basis
超过了固定宽高,那么flex-basis
则成为其 content
,如果flex-basis
比固定宽高小,那么以固定宽高为 content
。
对于固定元素的尺寸设定
3.元素存在 min-width[height] 或者 max-width[height]
如果flex-item
有min-width[min-height]
的限制,那么flex-item content
按照 min-width
值为下限,如果 flex-basis
的值大于 min-width[min-height]
那么flex-item content
以 flex-basis
计算。
如果flex-basis
的值小于 min-width[min-height]
那么flex-item content
以min-width[min-height]
计算:
如果 min-width[min-height]
的值已经超出了容器的尺寸,那么即使设置了 flex-shrink
。 CSS解析器也不会进行将这个item
的 content shrink,而是坚持保留它的min-width[min-height]
:
如果Flexbox 设置的min-width
超出了flex container 的范围, 不会对其进行压缩。
反之,如果设置了 max-width[height]
的值,那么设置flex-basis
无法超过这个值,对于flex-grow
也仅仅只会增长到 max-width[height]
这个上限。
在下面的章节,我们会仔细讨论这种情况下,布局的计算。
4.width[height]: auto; 优先级等于 flex-basis。
前面提到,如果给item同时设置了width[height]
和 flex-basis
的话。flex-item content以flex-basis
来决定。但是实际上默认的 width[height]: auto;
优先级是等于 flex-basis
的。
CSS解析器对比两者的值,两者谁大取谁 作为item的基本尺寸,如果一个item没有内容,flex-item content就会以flex-basis
来决定。
但是如果item有了内容,且内容撑开的尺寸比flex-basis
大,那么flex-item content就会以width[height]: auto;
来决定,且无法被 shrink。反之,如果比flex-basis
小,flex-item content就会以flex-basis
来决定:
width: auto;
内容长度比 flex-basis
大,则 flex-item content以内容长度来决定,且无法shrink
如果 flex-basis
的长度大于文字内容长度,那么flex-item content以 flex-basis
来决定
同时设置了flex-basis: 800px;
和 width: 1px;
flex-item content以 flex-basis
来决定,可以发生shrink
注意2号盒子我设置了 flex-shrink: 1;
1号盒子和3号盒子我设置了 flex-shrink: 0;
意思就是我将所有的需要shrink的空间都压到了2号盒子上,总共的需要 shrink的空间为 0 * 600 + 1 * 20 + 0 * 100 = -20
;而2号盒子只有20
的空间,理应被完全shrink变为0
,但是值得注意的是2号盒子并没有被完全 shrink,还保留了一个文字的距离。
除此之外,overflow: hidden;
也会影响
overflow: hidden;
把文字长度限制在了600px
; 小于 flex-basis: 700px;
所以flex-item content以flex-basis
来决定,可以 shrink。