type
status
date
slug
summary
tags
category
icon
password
Flow 布局又被称作是 Normal Flow,是 Web 中每个 Box 默认的布局方式。
相信不少 iOS 开发在初次接触前端的时候,都会被这个哪里都会看到,但哪里都不太能讲清楚到底是什么的概念所迷惑,总感觉很不好理解。
其实,这里的核心点在于,由于 Web 布局最早是为了做文字排版,所以和后来推出的 Flex 不同,Flow 布局的 “原子布局单位” 并不是每个元素所对应的 Box,而是有 Box(针对 Block Box)也有文本(针对 Inline Box)。
在 Flow 布局中有两种布局方向:inline direction 和 block direction。

Flow 布局的两个方向

当一个元素的 display 为 block/inline-block 时,其对应的 RenderObject 表现为一个 box(四四方方,不会折叠),同时在内部方向上,根据 writing-mode 其可以分为 inline direction 和 block direction:
notion image
notion image
我们可以称这样的一个 box 为 block container,在这个 block container 中,子元素只会按照如下两种方式排布:
notion image
  • 当所有子元素是 inline-level 的(inline 或者 inline-block),子元素在 inline direction 上排布
  • 否则(即子元素存在 block),子元素在 block direction 上排布
我们可以认为以上两条是 flow 布局的 “公理”,在现实情况中如果出现了和以上情况不符的,就用 “匿名 block” 来让实际情况符合以上两条公理

匿名 Box 的生成规则

实际 dom 结构中,可能会出现既有 inline 也有 block 的情况,这种情况下,当前容器需要将那些 inline 子元素包裹一个匿名的 Block Box,然后按照 block 方式排布子元素。
例如 :
notion image
这部分包裹匿名 Box 的详细逻辑在另一篇 浏览器是如何生成 RenderObject 的 中已经详细阐述,此处不再赘述。

Flow 布局的职责

  • 确保 Flow 中的 Box 盒模型属性计算完毕
  • 将 Flow 中的 inline-level box 与文本混合排布
  • 将 Flow 中的 block-level box 纵向排布

浏览器是如何实现 Flow 布局的?

Block 方向(子元素都是 block)

  1. 首先当前 box 的 content box 的宽度
  1. 计算当前 box 的 padding、border,将 padding top、border top 添加到当前 box 的高度中
  1. 调用子元素的 layout,确定子元素的 width、height、margin 等
  1. 根据子元素的 margin top 确定元素的坐标 y 值,根据元素的 margin left 确定元素的坐标 x 值
    1. 如果是第一个元素,需要考虑与 parent box 的 margin top 的 collapse
    2. 否则,考虑与前一 box 的 margin collapse
  1. 将子元素的高度添加到当前 box 的总高度
  1. 对下一个元素重复 2-4
  1. 针对最后一个元素,计算一下其 margin bottom 与当前 box 的 margin bottom 的 collapse 策略,并添加 padding bottom、border bottom
  1. 布局挂载在当前 box 中的 positioned box
  1. 计算子元素是否有 overflow 的行为出现,并根据结果决定是否展示 scroll bar

Inline 方向(子元素都是 inline)

  1. inline waker 遍历所有的 inline-level box、floating box、line break box、text,建立 line box tree,并对 box 执行 layout
  1. 按照文本排版的规则,以一个字符或者一个 box 为单位进行排布

附录

其他 Flow 布局实现过程中需要考量的属性

  • 定位模式(position):
    • 相对定位(relative):影响子元素的位移
    • 绝对定位(absolute)、吸附定位(sticky):影响元素的最终宽高计算值
  • 盒模型:
    • 盒模型边界(box-sizing): 影响元素的最终宽高计算值
    • 固有宽高(img/video的 width/height属性):影响元素的最终宽高计算值
    • 负 margin:影响子元素位移
    • 上下边距坍缩:影响 block、inline 自身高度计算
    • 宽高最大值、最小值(min/max-width/height):影响元素的宽高计算
    • direction/writing-mode:影响宽高的计算流程
    • aspect-ratio:影响元素的最终宽高计算值
    • 纵向排布(vertical-align):影响处于 inline formatting context 中的元素的位移
  • 文本:
    • 字符溢出(overflow-wrap/hyphens/text-overflow/white-space):影响带有文本的元素的最终宽高计算值
    • 字符排版
      • vertical-align:影响单个 inline 元素的位移
      • text-align:影响 block 内文本的左右边缘
  • 层级关系(z-index):影响布局的计算对象(z-index 不同的元素应该分别布局)
  • 浮动(float):影响 block 容器高度,影响 inline 容器的宽度
浏览器是怎么做 CSS 测试的?为什么我们要使用 RVM / Bundler ?