Flex Layout¶
Flex:CSS Flexible Box Layout,既:Flexbox(弹性盒布局)。顾名思义,就会了解两件事儿:
-
有 Box 就有 Box 中存放的东西:
-
我们管这个 Box 叫做 Flex Container(Flex 容器);
-
我们管放在 Box 中的“东西”叫做 Flex Item(Flex 项目),没有特别,只是放入了 FlexBox 中而已;
-
既然有 Flexbox(弹性盒布局),那么就有它的“兄弟”布局,这里先提前预报:
-
Block Layout(块级布局):默认文档流。不写
display: flex,它并不是“不是容器”,它仍然是容器,只是默认容器(block container),而不是 flex 容器。 - Inline Layout(行内布局)
- Grid Layout(网格布局):二维
- Multi-column Layout(多列布局)
- Box Alignment(盒子对齐)
Flex Layout(Flex Box)到底是个什么?¶
准确说,它不是“布局工具”,它是一个“受约束的空间分配系统”,有两个核心约束:
- 约束 1:父元素给了多少空间(height chain)
- 约束 2:子元素允许缩多少(minHeight)
这个“受约束的空间分配系统”的三种“影响方向”:
- 向下控制(核心):
display:flex→ 控制 children 布局 - 自我控制:
flex:1→ 控制自己如何分配空间 - 向上传递(非主动控制):内容 → 撑大父元素(自然流)
为什么 height: 100% 经常“看似写了但没用”?¶
因为 height: 100% 的含义是“等于父元素的高度”。如果父元素高度是 auto(由内容撑开),那 100% of auto 还是 auto,不会给你一个确定高度。很多文章把这称为“高度链断了”,需要从 html/body/#root 一路检查。
height: 100% 或 flex: 1 想要计算成一个确定值,需要祖先节点逐层提供可计算的高度约束。
为什么 minHeight: 0 在 Flex 里这么关键?¶
关键规则:flex item 默认 min-height/min-width 是 auto。
很多开发者以为 flex item 默认最小尺寸是 0,但实际上在 Flexbox 下,flex item 的 min-width/min-height 默认是 auto,也就是“最小尺寸不能小于内容的最小内容尺寸(min-content size)”。这会导致:
- 你明明
flex: 1想让它在有限空间内缩小; - 但它说“我最少得把内容装下”;
- 于是它不肯缩,反而把父容器撑大,滚动也可能失效。
在工程文章里经常用一句话总结: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% 就是跟父元素一样高。
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,控制“如何分配剩余空间”和“空间不足如何收缩”。
height: 100% 的含义真的“全等于父元素高度”吗?适用场景有限制吗?¶
它的核心含义确实是:百分比高度相对父元素的高度。
height: 100% 的“100%”是个相对值:相对于包含块(containing block)的高度(通常可以理解为父元素提供的可用高度)。
但“任何情况下都全等”并不成立。原因是:父元素的高度如果不是可计算的确定值,那这个百分比高度就无法变成具体数字,它可能退化为 auto 或表现为“不起作用”。很多工程文章把这称作“高度链断了”。
典型限制如下:
- 父元素高度是
auto(由内容撑开),则子元素height:100%没有明确参照,往往无法得到“填满窗口”的效果; height:100%更适合用在“父高度明确”的场景,比如父是100vh、px、或已经由上层链路明确传递出来的100%。
所以:height:100% 不是万能钥匙,它强依赖“父高度可计算”。
min-height / min-width 默认是 auto,auto 是什么含义?¶
auto 不是一个数字,它是一个规则。
auto 在 CSS 里是一个关键字(keyword),表示“由布局算法根据上下文决定”。它不是 0,也不是某个固定值,其结果可能是一个长度,也可能和内容尺寸有关。
在 Flexbox 里,min-height:auto 特别关键。大量 Flex/滚动 bug 的根源就是:flex item 默认最小尺寸(min-height / min-width)不是 0,而是 auto,这会导致它“不愿意缩到比内容更小”,从而把容器撑开、滚动失效、兄弟元素被挤压。
很多文章把这个现象解释为:默认最小尺寸会与 flex-shrink(收缩)产生冲突,导致你以为的 flex:1 “失灵”。解决办法就是显式设置 min-height:0 或 min-width:0,解除默认最小尺寸限制。
可以直接用的工程级规则(记住这三条就够)¶
- 要想子元素
height:100%生效,先保证父元素高度“可计算”(高度链不断); - 在垂直 flex 布局里,想让内容区可滚动、不撑爆,关键层要写
min-height:0(解除默认min-height:auto); display:flex是容器规则,flex:1是子项伸缩规则,两者不是替代关系,是“舞台 vs 演员”。
display:flex 的作用是:“把当前节点变成一个 layout 系统(容器),管辖它的 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)。
display 不是“外观属性”,而是“选择布局算法(layout algorithm)”。
所以:
display:flex= 启用 flex layout algorithmdisplay:block= 启用 block flow algorithmdisplay:grid= 启用 grid algorithm
注意:元素没变(还是那个 div),变的是“怎么解释、计算它的位置和子元素”。
flex: 1¶
“1”不是普通的长度数值,而是“比例权重”,但它自己不知道分母是多少。
flex:1 不等于“占满空间”。
很多人认为 flex:1 = 100%,这是错误的。它的真正含义是:在剩余空间里按比例分配,权重是 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压缩