Flex Layout¶
Flex:CSS Flexible Box Layout,既:Flexbox(弹性盒布局)。顾名思义,就能了解两件事儿:
-
有
Box就有Box中存放的东西:- 我们管这个
Box叫做Flex Container(Flex容器); - 我们管放在
Box中的“东西”叫做Flex Item(Flex项目),没有特别,只是放入了FlexBox中而已;
- 我们管这个
-
既然有 Flexbox(弹性盒布局),那么就有它的“兄弟”布局,这里先提前预报:
- Block Layout(块级布局):不写
display属性时,默认是 Block Layout; - Inline Layout(行内布局);
- Grid Layout(网格布局):二维;
- Multi-column Layout(多列布局);
- Box Alignment(盒子对齐)。
- Block Layout(块级布局):不写
Inline Layout、Block Layout、Flex Layout、Grid Layout、Multi-column Layout 都可以看作不同的布局模型(layout models),区别在于它们处理的对象和空间分配规则不同。
那么谁在“决定”一个 Box 是哪种类型的 Box 呢?
Box 元素的 display 属性并不是“外观属性”,而是“选择布局算法(layout algorithm)”。
所以:
display:flex= 启用flex layout algorithm;display:block= 启用block flow algorithm;display:grid= 启用grid algorithm。
注意:元素没变(还是那个 div 容器),变的是“怎么解释、计算它的位置和子元素”。
Flex Layout(Flex Box)到底是个什么?¶
它是一个“受约束的空间分配系统”,要了解它的一条链、两个约束、三个方向。
-
一条控制链:
Flex Box不同于其他的容器,它不是自己设置自己就可以了,而是 祖先 --> 父亲 --> 自己(子) 这一连串的设置共同控制、设置、分配了一个空间。 -
两个核心约束:
- 约束 1:父元素给了多少空间(
height chain); - 约束 2:子元素允许缩多少(
minHeight)。
- 约束 1:父元素给了多少空间(
-
三种“影响方向”:
- 向下控制(应用于
Box上):display:flex--> 控制children布局; - 自我控制(应用于
Box中的Item,这里是Flex Item):flex:1--> 控制自己如何占有空间; - 向上传递(非主动控制):
Flex Item占有空间的方式和内容多少 --> 撑大父元素(自然流)。
- 向下控制(应用于
关于一条控制链需要说明的几个问题¶
为什么 height: 100% 经常“看似写了但没用”?¶
因为 height: 100% 的含义是“等于父元素的高度”。如果父元素高度是 auto(由内容撑开),那 100% of auto 还是 auto,不会给你一个确定高度。很多文章把这称为“高度链断了”,需要从 html/body/#root 一路检查。
Note
height: 100% 或 flex: 1 想要计算成一个确定值,需要祖先节点逐层提供可计算的高度约束。
minHeight: 0 与 minHeight: auto的区别¶
minHeight:、min-width:是 Flex Item 的非常关键的设置属性;- 关键规则:flex item 默认
min-height/min-width是auto,而不是 0; - flex item 的
min-width/min-height默认是auto,意味着“最小尺寸不能小于内容的最小内容尺寸(min-content size)”
min-width/min-height:auto(默认值),这会导致:
- 你明明
flex: 1想让它在有限空间内缩小; - 但它说“我最少得把内容装下”;
- 于是它不肯缩,反而把父容器撑大,滚动也可能失效。
Note
flex: 1 失效、滚动不出现,很多时候是默认 min-height: auto 在阻止元素缩小
min-height: 0 到底改变了什么?¶
它做了一件很“硬核”的事:把最小高度从“内容决定”改成“允许缩到 0”。这样 flex-shrink 才能真正生效,子元素才会被压缩到父容器分配的高度内;如果内容超了,就交给 overflow(如 auto)在内部滚动,而不是把外层撑开。
height: 100% vs minHeight: 0:它们看起来都在控制 height,有什么关系?¶
这两个都“像是在管高度”,但它们控制的是完全不同的层面。
height: 100%:在做“目标高度”或“高度参照”。作用是告诉元素“你应该有多高”(相对父元素)。前提是父元素必须有可计算高度,否则无意义。
min-height: 0:在做“最小高度下限”。作用是告诉浏览器“你最少可以缩到多少”(覆盖默认 auto)。它解决的是 flex item “不肯缩小”导致撑破布局的问题。
简单总结¶
height: 100%解决“你该有多高”;min-height: 0解决“你能不能被压到那么高”。min-height: auto(默认)的实际含义是:这个元素最低不能小于内容高度(min-content height)。如果内容很高,元素就不肯缩小,可能导致父容器被撑大,滚动失效。height: 100%的作用是定义“目标高度”(你想变多高)。它依赖父高度约束,不能是auto,否则100%无法计算,等于auto。举例来说,height:100%就是跟父元素一样高。
Important
height: 100% 必须依赖父高度约束,父高度不能是 auto,否则 100% 无法计算,等于 auto
flex: 1本质是flex-grow / flex-shrink / flex-basis的简写,等价于flex: 1 1 0%,即flex-grow: 1; flex-shrink: 1; flex-basis: 0%;。
容易出错的设置¶
display: flex 与 flex: 1 是什么关系?有什么区别?¶
display: flex:
- 让父元素变成
Flex容器; - 写在容器(
parent)上:display: flex(或inline-flex); - 含义:开启
Flexbox布局模型,容器的直接子元素成为flex items,参与Flex排版与伸缩。
flex: 1:
- 让子元素按比例伸缩;
- 写在
flex item(child)上:flex: 1; - 它是三个属性的简写:
flex-grow、flex-shrink、flex-basis,控制“如何分配剩余空间”和“空间不足如何收缩”。
flex: 1¶
- “1”不是普通的长度数值,而是“比例权重”,但它自己不知道分母是多少;
flex:1不等于“占满空间”;
很多人认为 flex:1 = 100%,这是错误的。它的真正含义是:
- 在剩余空间里按比例分配,权重是
1,但自己不知道兄弟们的权重,自然也就不知道自己的这个1到底占多少权重; - 剩余空间的计算方式是:父容器的总空间减去已占用空间(由
flex-basis或内容决定); flex-grow的值是“相对权重”,分母等于当前flex行内所有item的权重总和。
举个最直观的例子:
如果剩余空间是 300px:
- 总权重 =
1 + 2 = 3 - A →
100px - B →
200px
flex-grow 只分“剩余空间”¶
注意:它不是分配整个容器,而是分配剩余空间(free space)。
“剩余空间” = 容器分配给这一行的空间 − 所有子元素的“基础占用空间”。
先占空间的,是“基础尺寸(flex-basis / width / 内容)”这一层。
顺序如下。
CSS Flex 的本质不是“占空间”,而是:在约束条件下求解一个分配结果。空间分配优先级如下:
-
基础空间(
Base Size)第一优先flex-basis(基础尺寸,如果设置了)- 否则
width / height(如果设置了) - 否则内容尺寸(
content size)
-
瓜分剩余空间(
Free Space)第二优先- 才进入:
flex-grow分配
- 才进入:
-
如果空间不够(负剩余空间),进入另一套系统
flex-shrink压缩
可以直接用的工程级规则¶
- 要想子元素
height:100%生效,先保证父元素高度“可计算”(高度链不断); - 在垂直
flex布局里,想让内容区可滚动、不撑爆,关键层要写min-height:0(解除默认min-height:auto); display:flex是容器规则,flex:1是子项伸缩规则,两者不是替代关系,是“舞台 vs 演员”。display:flex的作用是:“把当前节点变成一个layout system(容器),管辖它的children”。
如果不是 flex 容器:
flex:1不起作用;justify-content无效。
CSS 属性分两类¶
-
类 1:独立属性(
Universal)backgroundcolorborderpaddingmargin
这类属性不依赖
layout system,在任何box上都生效。 -
类 2:依赖
layout context的属性。属于
flex container的:justify-contentalign-itemsflex-direction
这类属性必须配合
display: flex;才有意义。属于
flex item的:flexalign-selforder
这类属性要求父元素是
flex container,否则会被忽略(不是报错,而是silently ignore)。
Note
display 不是“外观属性”,而是“选择布局算法(layout algorithm)”。所以:
1 2 3 | |
注意:元素没变(还是那个 div),变的是“怎么解释、计算它的位置和子元素”。