视觉格式化模型
CSS 视觉格式化模型(visual formatting model) 是用来处理和在视觉媒体上显示文档时使用的计算规则。该模型是 CSS 的基础概念之一。
什么是视觉格式化模型
视觉格式化模型会根据CSS盒子模型将文档中的元素转换为一个个盒子。——MDN
可以理解为,Web页面都是由一个个盒子组成的,(因为任何元素都可以被视为一个盒子),而视觉格式化模型是一套规则,用来计算元素转换为盒子的规则。而页面的布局都是由这些盒子的所处的各处位置组合而成。那么理解元素怎样转成盒子的规则,就能理解Web页面是怎样布局的。每个盒子的布局由以下因素决定的:
- 盒子的尺寸: 精确指定、由约束条件指定或没有指定
- 盒子的类型: 行内盒子(inline)、行内级盒子(inline-level)、原子行内级盒子(atomic inline-level)、块盒子(block)
- 定位方案(positioning scheme): 普通流定位、浮动定位或绝对定位
- 文档树中的其它元素: 即当前盒子的子元素或兄弟元素
- 视口尺寸与位置
- 所包含的图片的尺寸
- 其他的某些外部因素
那么视觉格式化模型和CSS盒子模型是一样的东西么?
并不是一样的模型,视觉格式化模型是元素转换为盒子的规则计算盒子位置的模型,换转为盒子后再有相应的CSS盒子模型,CSS盒子模型是由四个部分组成由内容边界(Content edge)、内边跟边界(Padding Edge)、边框边界(BorderEdge)、外边边框边界(Margin Edge),由这四部分来计算盒子尺寸(width
、height
、padding
、border
和margin
)该文章里不详述。
盒子的生成
盒子的生成是 CSS 视觉格式化模型的一部分,用于从文档元素生成盒子。不同的元素会生成不同类型的盒子,不同的盒子类型格式化方法也是不一样的。盒子中可以包含一个或多个盒子,CSS的视觉格式化模型会根据盒子的包含块(Containing Block,即包含其它盒子的块)的边界来渲染盒子。通常,盒子会创建一个包含其后代元素的包含块,但是盒子并不会被包含块限制住,盒子里面的布局会撑破包含块,使超出边界,这在CSS中通常被叫溢出。
盒子生成的类型取决于CSS display
属性,主要分下面几类:
块级元素与块盒子
当元素的 display
设为 block
、list-item
或 table
时,该元素将成为块级元素。一个块级元素会被格式化成一个块,默认按照垂直方向依次排列。
每个块级盒子都会参与块格式化上下文BFC(block formatting context)的创建,每个块级元素都至少生成一个块级盒子,有时甚至会生成多个块级盒子。
一个块级盒子包含子块级盒子的时候就会成为容器,称为块容器盒子(block container box)。块容器盒子要么只包含其它块级盒子,要么只包含行内盒子并同时创建一个行内格式化上下文(inline formatting context)。如果同时包含两者的情况,就会在相邻的行内级盒子外创建匿名块盒子包裹行内级盒子。
匿名块盒子
匿名块盒子(anonymous box)是指CSS选择器不能作用于该类盒子,所以它不能被赋予样式。它的CSS样式都是继承过来的, CSS属性值都为 inherit
, 而所有不可继承的 CSS 属性值都为 initial
。
行内级元素和行内盒子
如果一个元素的 display
属性为 inline
、inline-block
或 inline-table
,则称该元素为行内级元素。它不会生成内容块,视角上他会与其它行内级内容一起显示为多行。典型的例子是包含多种格式内容(如强调文本、图片等)的段落,就是由行内级元素组成的。
行内级元素会生成行内级盒子,该盒子同时会参与行内格式化上下文(inline formatting context)的创建。行内盒子既是行内级盒子,也是一个其内容会参与创建其容器的行内格式化上下文的盒子,比如所有具有 display:inline
样式的非替换盒子。如果一个行内级盒子的内容不参与行内格式化上下文的创建,则称其为原子行内级盒子。而通过替换行内级元素或 display 值为 inline-block
或 inline-table
的元素创建的盒子不会像行内盒子一样可以被拆分为多个盒子,原子行内级盒子,永远都不会换行,会被视为一整个原子一样。例子
匿名行内盒子
类似于块盒子,CSS引擎有时候也会自动创建一些行内盒子。这些行内盒子无法被选择符选中,因此是匿名的,它们从父元素那里继承那些可继承的属性,其他属性保持默认值 initial
。
一种常见的情况是CSS引擎会自动为直接包含在块盒子中的文本创建一个行内格式化上下文,在这种情况下,这些文本会被一个足够大的匿名行内盒子所包含。但是如果仅包含空格则有可能不会生成匿名行内盒子,因为空格有可能会由于 white-space
的设置而被移除,从而导致最终的实际内容为空。
其它类型的盒子
其它类型盒子有:
- 行盒子,行盒子由行内格式化上下文创建,用来显示一行文本。浮动定位时,行盒子会自动包围浮动元素。
- Run-in 盒子,通过
display:run-in
来定义,它可以是块盒子,也可以是行内盒子,取决于紧随其后的盒子类型。 - 其它模型引入的盒子, 除了IFC 行内格式化上下文和BFC 块格式化上下文,还有其它的模型会生成盒子,比如:
1)表格内容模型, 可能会创建一个表格包装器盒子和一个表格盒子,以及多个其他盒子如表格标题盒子等。
2)多列内容模型可能会在容器盒子和内容之间创建多个列盒子
3)实验性的网格内容模型或flex-box内容模型同样会创建一些其他种类的盒子
定位规则
生成盒子之后,CSS引擎就需要定位它们以完成布局定位,可以说盒子就是定位的基本单位。定位时,有三种定位方案:
常规流(Normal flow)
- 在常规流中,依次按照盒子一个接着一个水平左右排列,没位置换行。
- 在块级格式上下文(BFC)中,盒子依次垂直方向排列。
- 在行内格式上下文(IFC)中,盒子则水平方向排列。
- 当
position
为static
或relative
,并且float
为none
时会触发常规流。 - 对于静态定位(static positioning),
position: static
, 此时盒子的位置会根据普通流所计算出来的确切位置来定位。 - 对于相对定位(relative positioning),
position: relative
, 此时盒子会根据偏移属性top
,bottom
,left
和right
,进行偏移。即使有偏移,仍然保留原有的位置,其它常规流不能占用这个位置。
浮动(Floats)
- 一个盒子的
float
值不会为none
,并且position
为static
或relative
时,该盒子为浮动定位,称为浮动盒子(floating boxes)。 - 浮动盒子会浮动到当前行的开始或尾部位置。
- 浮动盒子浮动后,其它普通流盒子会环绕它的周边,除非设置
clear
属性。 - 不管左浮动或右浮动,行盒子都会伸缩以适应浮动盒子的大小。
绝对定位(Absolute positioning)
- 元素的
position
为absolute
或者fixed
,则为绝对定位。 - 绝对定位盒子,会从常规流中移除不再保留原位置,不再影响其它常规流的正常排序布局。
- 它的定位相对于它的包含块计算,根据CSS属性
top
,bottom
,left
和right
来判断。 - 对于
position: absolute
, 元素定位将相对于最近的一个relative
、fixed
或absolute
的父元素决定,如果没有则相对于body
。 - 如果固定位置的元素
fixed
的来说, 会视包含块为整个视口,会相对于视口进行绝对定位。因此滚动时元素位置并不会改变。