在盒模型中我们了解到,在 CSS 的世界中,任何一个元素都是一个盒子,它具有一个专业术语,即盒模型。而视觉格式化模型会根据 CSS 盒模型将文档中的元素转换为一个个盒子。
Web 页面(文档树)是由很一个个盒子组成(因为任何元素都可以被视为是一个盒子),而视觉格式化模型却是一套规则,用来计算元素转换为盒子的规则。而页面的布局都由这些盒子的所处的各处位置组合而成。那么理解了元素怎么转成盒子的规则,就理解了 Web 页面是怎么布局。 而每个盒子的布局主要由以下几个因素决定:
盒子的尺寸:精确指定、由约束条件指定或没有指定
盒子的类型:行内盒子(inline)、行内级盒子(inline-level)、原子行内级盒子(atomic inline-level)和块盒子(block)
定位方案:普通流定位、浮动定位或绝对定位
文档树中的其它元素:即当前盒子的子元素或兄弟元素
视窗尺寸与位置
所包含的图片的尺寸
其他的某些外部因素
CSS 的盒模型是计算盒子尺寸( width 、 height 、 padding 、 border 和 margin 来决定);视觉格式化模型是用来计算盒子位置(由前面提到的七个因素来决定) !
盒子的定位和大小都是参考一个矩形边缘来计算的,而这个矩形就是元素的容器块。一个元素的容器块大概定义如下:
position:fixed,它的容器块一般由视窗生成position:absolute,它的容器块就由设置了position值为relative、absolute或fixed的最近父元素生成,如果父级元素都没有设置,则由根元素生成块级盒子(Block-level Box),由块级元素生成。一个块级元素至少会生成一个块级盒子,但也有可能生成多个(例如列表项元素)。
行内级盒子(Inline-level Box),由行内级元素生成。同样的,一个行内元素至少会生成一个行内级盒子。行内级盒子包括行内盒子和原子行内级盒子两种,区别在于该盒子是否参与行内格式化上下文的创建。
简单地说,块元素生成块组盒子,行内元素或行内级元素生成行内级盒子。两种盒子可以通过display来进行切换。
块盒子(Block Box),如果一个块级盒子同时也是一个块容器盒子,则称其为块盒子。除具名块盒子之外,还有一类块盒子是匿名的,称为匿名块盒子(Anonymous Block Box),匿名盒子无法被 CSS 选择器选中。
行内盒子(Inline Box)由非替换元素(Non-replaced Element)生成,属于行内级盒中的一种。除了行内盒子之外,其他的行内级盒子都是原子行内级盒(Atomic Inline-level Box),它的典型特征就是作为一个整体,不能拆分换行。同样的,行内盒子也有匿名行内盒(Anonymous Inline Box)。对于没有任何元素包裹的直接文本,CSS引擎会为其创建匿名行内盒。
替换元素: 替换元素就是浏览器根据元素的标签和属性,来决定元素的具体显示内容。替换元素是其内容不受CSS视觉格式化模型控制的元素
常见的替换元素: img、input、textarea、select、object、video
非替换元素: 大多数元素都是非替换元素,标签内的内容就是要渲染的内容
简单地说,参与行内格式化上下文创建的行内盒子称为行内盒子。
原子行内级盒子(Atomic Inline-level Box),不参与行内格式化上下文创建的行内级盒子。原子行内级盒子一开始叫做原子行内盒子(Atomic Inline Box),后被修正。原子行内级盒子的内容不会拆分成多行显示。
行盒(Line Box)和行内盒是不一样的。行盒是由行内格式化上下文(Inline Formatting Context)产生的盒子,用于表示一行。行盒从包含块的一边排版到另一边。一般情况下,浏览器为会每行创建一个看不见的行盒。
块容器盒子(Block Container Box 或 Block Containning Box),块容器盒子侧重于当前盒子作为容器角色,它不参与当前块的布局和定位,它所描述的仅仅是当前盒子与其后代之间的关系。换句话说,块容器盒子主要用于确定其子元素的定位、布局等。
块级元素(Block-level Element)是指元素的display 值为block、list-item、table、flex 和 grid 等,该元素将成为块级元素。元素是否是块级元素仅是元素本身的属性,并不直接用于格式化上下文的创建或布局。
行内级元素(Inline-level Element)是指元素的 display 值为 inline、inline-block、inline-table、inline-flex 和 inline-grid 等,该元素将成为行内级元素。与块元素一样,元素是否是行内级元素仅是元素本身的属性,并不直接用于格式化上下文的创建或布局。
在CSS中格式化上下文有很多种,比如IFC(Inline Formatting Context) 、BFC(Block Formatting Context) 、FFC(Flexbox Formatting Context) 和GFC(Grid Formatting Contexgt) 等。而这些格式化上下文的集合可以称作视觉格式化模型。
不同的盒子使用的是不同的格式化上下文(Formatting Context)来布局,每个格式化上下文都拥有自己不同的渲染规则,而这些规则是用来决定其子元素如何定位,以及和其他元素的关系。
盒子的生成是 CSS 视觉格式化模型的一部分,用于从文档元素生成盒子。盒子有不同的类型,不同类型的盒子的格式方法也有所不同,不同的盒子也会影响元素或其后代元素的行为。在 CSS 中,通常使用 display 属性来明确盒子的类型。
CSS 的 display 属性的值,将导致文档里的元素生成一个主盒(Principal Box)以包含后代盒子和内容,同时其自身也是参与到定位方案中的盒子。而有些元素除了会生成主盒之外,还可能会生成额外的盒子。比如设置了 display 值为 list-item 元素。这些额外的盒子的放置位置与主盒有关。
盒子之间的类型还可以使用 display 的不同值来进行切换。在 display 中还有两个不同的值 none 和 contents ,可以用来控制盒子是否应该显式。
元素的 display 值不是 none 或 contents 时,元素即可生成一个盒子,盒子的类型由其值的类型来决定
元素的 display 值是 none 时,元素及其后代元素都不会生成盒子
元素的 display 值是 contents 时,元素自身不会生成盒子,但其后代元素依旧会根据 display 生成相应的盒子
当元素的 display 为block、list-item、table、flex 或 grid 时,该元素将成为块级元素。一个块级元素会被格式化成一个块,比如我们熟悉的 div、p、li 等元素。这些块级元素默认按照从左到右自上而下依次堆叠。
而每个块级盒子都会参与块格式化上下文(Block Formatting Context,俗称BFC)的创建,每个块级元素都会至少生成一个块级盒子,即主块级盒子(Principal Block-level Box)。有一些元素除了会生成主块级盒子之外,还会生成额外的盒子。比如 display 取值为 list-item 的元素,除了生成主块级盒子之外,还会生成一个Marker标记盒子(Marker标记是指类似项目符号的标记),而那些生成列表项的元素可能会生成更多的盒子。
大多数元素只生成一个主块级盒子。
主块级盒子包含由后代元素生成的盒子以及内容,同时也会参与定位方案。一个块级盒子可能也是一个块容器盒子。块容器盒子(Block Container Box)要么只包含其他块级盒子,要么只包含行内盒子并同时创建一个行内格式化上下文(Inline Formatting Context,俗称IFC)。
注意,块级盒子与块容器盒子是不同的,这一点很重要。块级盒子描述了元素与其父元素和兄弟元素之间的行为;块容器盒子描述了元素跟其后代之间的行为。这些块级盒子并不是块容器盒子,比如table;而有些块容器盒子也不是块级盒子,比如非替换行内块和非替换表格单元格。
如果一个盒子同时既是块容器盒子又是块级盒子的话,该盒子被称为块盒子(Block Box)。
那么这里我们简单的理一理块(Block) 、包含块(Containing Block) 、盒子(Box) 、块级盒子(Block-level Box) 、块盒子(Block Box) 、块容器盒子(Block Containning Box) 和块级元素(Block-level Element) 之间的关系:
元素display的值为block、list-item、table、flex和grid时,该元素会生成一个块级元素(Block-level Element)
块级元素(Block-level Element)会生成一个块级盒子(Block-level Box)
块级盒子会参与块格式化上下文(BFC) 的创建
块级盒子(Block-level Element)描述了元素与其父元素和兄弟元素之间的行为
块容器盒子(Block Containning Box) 描述了元素跟其后代之间的行为。要么只包含块级盒子(Block-level Box) ,要么只包含行内级盒子(Inline-level Box) 。有的块容器盒子不是块级盒子,同样块级盒子有时也不是块容器盒子
同时是块级盒子(Block-level Box) 和块容器盒子(Block Containning Box) 的盒子被称作是块盒子(Block Box)
除此之外,还有匿名块盒子(Anonymous Block Box)
CSS的display有很多个属性值,当元素的display属性的值为inline、inline-block、inline-table、inline-flex或inline-grid时,该元素被称为行内级元素。显示时,它不会生成内容块,但是可以与其他行内级内容一起显示为多行。比如,包含多种格式内容(比如strong、img等)的段落p,就可以由行内级元素组成。
行内级元素会生成行内级盒子,该盒子同时会参与行内格式化上下文(Inline Formatting Context)的创建。行内盒子既是行内级盒子,也是一个其内容参与创建其容器的行内格式化上下文的盒子,比如所有具有display: inline样式的非替换盒子。如果一个行内级盒子的内容不参与行内格式化下下文的创建,则称其为原子行内级盒子。而通过替换行内级元素或display值为inline-block、inline-table、inline-flex或inline-grid的元素创建的盒子不会像行内盒子一样可以被拆分为多个盒子。
简单归纳一下:
元素display的值为inline、inline-block、inline-table、inline-flex或inline-grid时,元素则为行内级元素(Inline-level Element)
行内级元素会生成行内级盒子(Inline-level Box),会参与IFC的创建
同样的,也会创建一个匿名行内盒子
匿名盒子分为块匿名盒子和行内匿名盒子。在某些情况下进行视觉格式化时,需要添加一些增补性的盒子,这些盒子无法被CSS的选择器选中,而这种盒子被称为匿名盒子(Anonymous Box) 。
CSS选择器不能作用于匿名盒子(Anonymous Box),所以无法设置样式。也就是说,此时所有可继承的CSS属性值都为inherit,而所有不可继承的CSS属性值都为initial。
除了上述说到的盒子,在CSS中还定义了几种内容模型,这些模型同样可以应用于元素。这些模型一般用来描述布局,它们可能会定义一些额外的盒子类型:
表格内容模型:可能会创建一个表格包装器盒子和一个表格盒子,以及多个其他盒子如表格标题盒子等
多列内容模型:可能会在容器盒子和内容之间创建多个列盒子
Flexbox内容模型:可能会创建一个弹性盒子
Grid内容模型:可能会创建一个网格盒子
CSS中的格式化上下文有很多种,除了大家熟悉的BFC、IFC之外还有由Flexbox布局创建的FFC和Grid布局创建GFC等。这些统称为CSS格式化上下文,也被称作视觉格式化模型。而CSS视觉格式化模型是用来处理文档并将它显示在视觉媒体上的机制。简单地说,就是用来控制盒子的位置,即实现页面的布局。
格式化上下文也可以说是CSS视觉渲染中的一部分,其主要作用是决定盒子模型的布局,其子元素将如何定位以及和其他元素的关系和相互作用。那么理解CSS格式化上下文有助于我们掌握各类CSS布局的关键。
行内格式化上下文(Inline Formatting Context),简称IFC。主要用来规则行内级盒子的格式化规则。
IFC的行盒的高度是根据包含行内元素中最高的实际高度计算而来。主要会涉及到CSS中的font-size、line-height、vertical-align和text-align等属性。
行内元素从包含块顶端水平方向上逐一排列,水平方向上的 margin、border、padding 生效。行内元素在垂直方向上可按照顶部、底部或基线对齐。
当几个行内元素不能在一个单独的行盒中水平放置时,他们会被分配给两个或更多的(Vertically-stacked Line Box)垂直栈上的行盒,因此,一个段落是很多行盒的垂直栈。这些行盒不会在垂直方向上被分离(除非在其他地方有特殊规定),并且他们也不重叠。
垂直方向上,当行内元素的高度比行盒要低,那么 vertical-align 属性决定垂直方向上的对齐方式。
水平方向上,当行内元素的总宽度比行盒要小,那么行内元素在水平方向上的分部由 text-align 决定。
水平方向上,当行内元素的总宽度超过了行盒,那么行内元素会被分配到多个行盒中去,如果设置了不可折行等属性,那么行内元素会溢出行盒。
行盒的左右两边都会触碰到包含块,而 float 元素则会被放置在行盒和包含快边缘的中间位置。
下面这些规则都会创建一个行内格式化上下文:
IFC只有在一个块级元素中仅包含行内级元素时才会生成
内部的盒子会在水平方向,一个接一个的放置
这些盒子垂直方向的起点从包含块盒子的顶部开始
摆放这些盒子的时候,它们在水平方向上的padding、border和margin所占用的空间都会被考虑在内
在垂直方向上,这些盒子可能会以不同形式来对齐(vertical-align)
能把在一行上的盒子都完全包含在一行行盒(Line Box),行盒的宽度是由包含块和存在的浮动来决定
IFC中的行盒一般左右边都紧贴其包含块,但是会因浮动元素的存在发生变化。浮动元素会位于IFC与行盒之间,使得行盒宽度缩短
当行内级盒的总宽度小于包含它们的行盒时,其水平渲染规则则由text-align来确定
当行内盒超过行盒的宽度时,它会被分割成多个盒子,这些盒子被分布在多个行盒里。如果一个行内盒不能被分割,则会溢出行盒
IFC主要用于:
行内元素按照 text-align 进行水平居中
行内元素撑开父元素高度,通过 vertical-align 属性进行垂直居中
块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
BFC实际上就是页面中一块渲染区域,该区域与其他区域隔离开来。容器里面子元素不会影响到外部,外部的元素也不会影响到容器里的子元素。
BFC 内部的盒子会从上至下一个接着一个顺序排列。BFC 内的垂直方向的盒子距离以 margin 属性为准,上下 margin 会叠加。每个元素的左侧最外层边界与包含块 BFC 的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。BFC 的区域不会与浮动元素的盒子折叠。BFC 的高度也会受到浮动元素的影响,浮动元素参与计算。
下面这些规则可以创建一个BFC:
根元素或包含根元素的元素
浮动元素(元素的 float 不是 none)
绝对定位元素(元素的 position 为 absolute 或 fixed)
行内块元素(元素的 display 为 inline-block)
表格单元格(元素的 display为 table-cell,HTML表格单元格默认为该值)
表格标题(元素的 display 为 table-caption,HTML表格标题默认为该值)
匿名表格单元格元素(元素的 display为 table、table-row、 table-row-group、table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot的默认属性)或 inline-table)
overflow 值不为 visible 的块元素
display 值为 flow-root 的元素
contain 值为 layout、content或 strict 的元素
弹性元素(display为 flex 或 inline-flex元素的直接子元素)
网格元素(display为 grid 或 inline-grid 元素的直接子元素)
多列容器(元素的 column-count 或 column-width 不为 auto,包括 column-count 为 1)
column-span 为 all 的元素始终会创建一个新的BFC,即使该元素没有包裹在一个多列容器中
块格式化上下文包含创建它的元素内部的所有内容。其主要使用:
创建独立的渲染环境
防止因浮动导致的高度塌陷
防止上下相邻的外边距折叠
Flex格式化上下文(Flexbox Formatting Context)俗称FFC。当display取值为flex或inline-flex,将会创建一个Flexbox容器。该容器为其内容创建一个新的格式化上下文,即Flex格式化上下文。
不过要注意的是,Flexbox容器不是块容器(块级盒子),下列适用于块布局的属性并不适用于Flexbox布局:
多列中的column-*属性不适用于Flexbox容器
float和clear属性作用于Flex项目上将无效,也不会把让Flex项目脱离文档流
vertical-algin属性作用于Flex项目上将无效
::first-line和::first-letter伪元素不适用于Flexbox容器,而且Flexbox容器不为他们的祖先提供第一个格式化的行或第一个字母
Grid格式化上下文(Grid Formaatting Context),俗称GFC。和FFC有点类似,元素的display值为grid或inline-grid时,将会创建一个Grid容器。该容器为其内容创建一个新的格式化上下文,即Grid格式化上下文。这和创建BFC是一样的,只是使用了网格布局而不是块布局。
网格容器不是块容器,因此一些假定为块布局设计的属性并不适用于网格格式化上下文中。特别是:
float和clear运用于网格项目将不会生效。但是float属性仍然影响网格容器子元素上display的计算值,因为这发生在确定网格项目之前
vertical-align运用于网格项目也将不会生效
::first-line和::first-letter伪元素不适用于网格容器,而且网格容器不向它们社先提供第一个格式化行或第一个格式化字母
本文转载自css重要概念:视觉格式化模型


本文作者:繁星
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!