跳转至

Flex Layout

Flex:CSS Flexible Box Layout,既:Flexbox(弹性盒布局)。顾名思义,就会了解两件事儿:

  1. 有 Box 就有 Box 中存放的东西:

  2. 我们管这个 Box 叫做 Flex Container(Flex 容器);

  3. 我们管放在 Box 中的“东西”叫做 Flex Item(Flex 项目),没有特别,只是放入了 FlexBox 中而已;

  4. 既然有 Flexbox(弹性盒布局),那么就有它的“兄弟”布局,这里先提前预报:

  5. Block Layout(块级布局):默认文档流。不写 display: flex,它并不是“不是容器”,它仍然是容器,只是默认容器(block container),而不是 flex 容器。

  6. Inline Layout(行内布局)
  7. Grid Layout(网格布局):二维
  8. Multi-column Layout(多列布局)
  9. Box Alignment(盒子对齐)

Flex Layout(Flex Box)到底是个什么?

准确说,它不是“布局工具”,它是一个“受约束的空间分配系统”,有两个核心约束:

  • 约束 1:父元素给了多少空间(height chain)
  • 约束 2:子元素允许缩多少(minHeight)

这个“受约束的空间分配系统”的三种“影响方向”:

  1. 向下控制(核心):display:flex → 控制 children 布局
  2. 自我控制:flex:1 → 控制自己如何分配空间
  3. 向上传递(非主动控制):内容 → 撑大父元素(自然流)

为什么 height: 100% 经常“看似写了但没用”?

因为 height: 100% 的含义是“等于父元素的高度”。如果父元素高度是 auto(由内容撑开),那 100% of auto 还是 auto,不会给你一个确定高度。很多文章把这称为“高度链断了”,需要从 html/body/#root 一路检查。

height: 100%flex: 1 想要计算成一个确定值,需要祖先节点逐层提供可计算的高度约束。

为什么 minHeight: 0 在 Flex 里这么关键?

关键规则:flex item 默认 min-height/min-widthauto

很多开发者以为 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: flexflex: 1 是什么关系?有什么区别?

display: flex:让父元素变成 Flex 容器。

写在容器(parent)上:display: flex(或 inline-flex)。

含义:开启 Flexbox 布局模型,容器的直接子元素成为 flex items,参与 Flex 排版与伸缩。

flex: 1:让子元素按比例伸缩。

写在flex item(child)上:flex: 1

它是三个属性的简写:flex-growflex-shrinkflex-basis,控制“如何分配剩余空间”和“空间不足如何收缩”。

height: 100% 的含义真的“全等于父元素高度”吗?适用场景有限制吗?

它的核心含义确实是:百分比高度相对父元素的高度。

height: 100% 的“100%”是个相对值:相对于包含块(containing block)的高度(通常可以理解为父元素提供的可用高度)。

但“任何情况下都全等”并不成立。原因是:父元素的高度如果不是可计算的确定值,那这个百分比高度就无法变成具体数字,它可能退化为 auto 或表现为“不起作用”。很多工程文章把这称作“高度链断了”。

典型限制如下:

  • 父元素高度是 auto(由内容撑开),则子元素 height:100% 没有明确参照,往往无法得到“填满窗口”的效果;
  • height:100% 更适合用在“父高度明确”的场景,比如父是 100vhpx、或已经由上层链路明确传递出来的 100%

所以:height:100% 不是万能钥匙,它强依赖“父高度可计算”。

min-height / min-width 默认是 autoauto 是什么含义?

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:0min-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)

  • background
  • color
  • border
  • padding
  • margin

这类属性不依赖 layout system,在任何 box 上都生效。

类 2:依赖 layout context 的属性。

属于 flex container 的:

  • justify-content
  • align-items
  • flex-direction

这类属性必须配合 display: flex; 才有意义。

属于 flex item 的:

  • flex
  • align-self
  • order

这类属性要求父元素是 flex container,否则会被忽略(不是报错,而是 silently ignore)。

display 不是“外观属性”,而是“选择布局算法(layout algorithm)”。

所以:

  • display:flex = 启用 flex layout algorithm
  • display:block = 启用 block flow algorithm
  • display:grid = 启用 grid algorithm

注意:元素没变(还是那个 div),变的是“怎么解释、计算它的位置和子元素”。

flex: 1

“1”不是普通的长度数值,而是“比例权重”,但它自己不知道分母是多少。

flex:1 不等于“占满空间”。

很多人认为 flex:1 = 100%,这是错误的。它的真正含义是:在剩余空间里按比例分配,权重是 1。剩余空间的计算方式是:父容器的总空间减去已占用空间(由 flex-basis 或内容决定)。

flex-grow 的值是“相对权重”,分母等于当前 flex 行内所有 item 的权重总和。

举个最直观的例子:

.container {
  display: flex;
}

.A {
  flex: 1;
}

.B {
  flex: 2;
}

如果剩余空间是 300px

  • 总权重 = 1 + 2 = 3
  • A → 100px
  • B → 200px

flex-grow 只分“剩余空间”

注意:它不是分配整个容器,而是分配剩余空间(free space)。

“剩余空间” = 容器分配给这一行的空间 − 所有子元素的“基础占用空间”。

先占空间的,是“基础尺寸(flex-basis / width / 内容)”这一层。

顺序如下。

CSS Flex 的本质不是“占空间”,而是:在约束条件下求解一个分配结果。空间分配优先级如下:

  1. 基础空间(Base Size)第一优先

  2. flex-basis(基础尺寸,如果设置了)

  3. 否则 width / height(如果设置了)
  4. 否则内容尺寸(content size)

  5. 瓜分剩余空间(Free Space)第二优先

  6. 才进入:flex-grow 分配

  7. 如果空间不够(负剩余空间),进入另一套系统

  8. flex-shrink 压缩