普通文档流(normal flow)到底是什么

3 阅读6分钟

学 CSS 布局时,几乎所有概念最后都会回到一个词:文档流
blockinlinepositionfloatabsoluteflexgrid……
你如果不理解“普通文档流”,后面很多现象都会觉得像玄学。
这篇文章就把它讲透。


目录


一、先说结论:文档流到底是什么

你可以先记住一句最重要的话:

普通文档流,就是浏览器默认摆放元素的一套基础规则。

当你什么都不特别设置时,页面里的元素会按照 HTML 的先后顺序,一个一个排下去。

浏览器会根据元素类型决定怎么放:

  • 块级元素:通常从上到下,一个接一个
  • 行内元素:通常在一行里,从左到右,放不下再换行

这套“默认怎么排”的规则,就是普通文档流。


二、为什么浏览器需要文档流

浏览器拿到 HTML 后,不可能把所有元素胡乱堆在一起,它必须有一套基础排版机制。

比如:

<h1>标题</h1>
<p>第一段文字</p>
<p>第二段文字</p>

浏览器天然知道应该这样排:

  1. 标题先出来
  2. 第一段在标题下面
  3. 第二段在第一段下面

这不是巧合,而是因为这些元素都在普通文档流里。

所以你可以把普通文档流理解成:

浏览器的默认排版秩序。

没有它,页面就没法自动形成结构。


三、普通文档流里元素是怎么排的

1. 按源码顺序排

文档流最基础的规则就是:

谁先写,谁先排。

例如:

<div>A</div>
<div>B</div>
<div>C</div>

默认情况下,页面就会按 A → B → C 的顺序排列。


2. 块级元素通常竖着排

例如:

<div>块1</div>
<div>块2</div>
<div>块3</div>

默认表现通常是:

  • 块1 一行
  • 块2 下一行
  • 块3 再下一行

因为块级元素在普通文档流中通常会独占一行。


3. 行内元素通常横着排

例如:

<span>A</span>
<span>B</span>
<span>C</span>

默认表现通常是:

  • A、B、C 在同一行
  • 放不下再自动换行

因为行内元素在普通文档流中通常按文本流规则排列。


四、块级元素和行内元素在文档流中的表现

1. 块级元素

默认特点:

  • 独占一行
  • 从上到下排列
  • 宽度通常尽量撑满父容器

常见例子:

  • div
  • p
  • h1 ~ h6
  • section
  • article

2. 行内元素

默认特点:

  • 不独占一行
  • 在一行里从左到右排列
  • 像文字一样参与排版

常见例子:

  • span
  • a
  • strong
  • em

3. 所以文档流并不是一种“单一排列方式”

它实际上同时包含了两套默认规则:

  • 块级格式的默认排法
  • 行内格式的默认排法

这也是为什么你看到 divspan 的默认表现完全不同。


五、什么叫“脱离文档流”

这是文档流里最核心的进阶概念。

所谓“脱离文档流”,可以先这样理解:

这个元素不再按照浏览器默认的那套排版秩序占位置了。

也就是说,它不再老老实实地按源码顺序、按块级/行内规则排在原来的位置里。

最直接的结果通常是:

  • 它原本的位置可能不再被它占着
  • 后面的元素会像它不存在一样继续排
  • 它会用另一套规则决定自己放哪儿

六、哪些东西会脱离普通文档流

1. position: absolute

绝对定位元素会脱离普通文档流。

例如:

.box {
  position: absolute;
  top: 0;
  left: 0;
}

效果通常是:

  • .box 不再占据原来位置
  • 后面的元素会顶上来
  • .box 自己按定位规则放到别处

2. position: fixed

固定定位也会脱离普通文档流。

.box {
  position: fixed;
  right: 20px;
  bottom: 20px;
}

它直接相对视口放置,不再按普通流排。


3. float

浮动元素比较特殊。

它不是像 absolute 那样完全独立,但也不再像普通块级元素那样老老实实占位。

所以通常也会被认为“脱离普通文档流的常规排列影响”。


七、为什么理解文档流这么重要

因为你在 CSS 里遇到的大量问题,本质都在问:

这个元素现在是不是还在普通文档流里?

例如:

  • 为什么父元素高度塌了?
  • 为什么元素重叠了?
  • 为什么后面的元素顶上来了?
  • 为什么 absolute 元素不占位置?
  • 为什么 float 后需要清除浮动?
  • 为什么 flex / grid 后子元素排法变了?

这些都和“是否按普通文档流排”直接相关。


八、几个最容易混淆的点

1. relative 不会脱离文档流

.box {
  position: relative;
  top: 10px;
}

它只是视觉上偏移了,但原来占的位置还在。

所以:

  • relative不脱离普通文档流
  • absolute / fixed脱离普通文档流

2. display: none 不是“脱离文档流”,而是直接没了

`display: none`` 的效果不是“它还在,但脱流了”,而是:

元素直接不参与渲染和布局了。

它比“脱流”更彻底。


3. flex / grid 不是简单“脱离文档流”

父元素设置 display: flexdisplay: grid 后,子元素不是跑没了,而是:

子元素不再按普通流的块/行内规则排列,而是按 flex / grid 规则排列。

这和 absolute 那种脱流不是一回事。


九、一张表总结

概念是否还按普通文档流排说明
普通块级元素从上到下,一个接一个
普通行内元素在一行中从左到右
position: relative还占原位置,只是视觉偏移
position: absolute脱离普通文档流
position: fixed脱离普通文档流
float部分脱离常规影响会改变普通流表现
display: flex 子项不按普通块/行内排按 flex 规则排
display: grid 子项不按普通块/行内排按 grid 规则排

十、结论

普通文档流本质上就是:

浏览器在没有特殊干预时,对页面元素进行默认排版的基础秩序。

你只要抓住这句话,很多 CSS 现象都会立刻变清晰:

  • 正常元素为什么会按顺序排
  • 为什么块级元素是竖着堆
  • 为什么行内元素是横着流
  • 为什么 absolute 会不占位置
  • 为什么布局一复杂就总绕回“文档流”

最后再压缩成一句最适合记忆的话:

学布局,先判断元素是不是还在普通文档流里。

这一步判断对了,后面大半问题都会变简单。