大前端学习笔记整理【二】CSS视觉格式化模型

时间:2023-03-08 16:32:26
1. 概念
在视觉格式化模型中,文档树中的每个元素都将会根据盒模型产生零到多个盒子。这些盒子的布局由如下因素决定:
  • 盒子的尺寸和类型
  • 定位策略(正常文档流,浮动或者绝对定位)
  • 和文档树中其他元素的关系
  • 额外的信息(比如视口的大小,图片的原始尺寸等)
1.1 视口(viewport)
连续媒体(continuous media)的UA(user agent/用户代理)通常会给用户提供一个视口,一般为一个窗口或者屏幕上的一片可视区域。用户通过这个视口查看文档(document)。当视口的大小改变时,UA可能会改变文档的布局。
当视口的大小比文档所渲染的区域(画布,canvas)小时,UA需要提供滚动机制。每个画布只能有至多一个视口,但是UA可以将一个文档渲染到多个画布上去(比如提供同一个文档的不同展示方式)。
1.2 包含块
在CSS2.1中,许多盒子的位置和大小都是根据一个叫做包含块(containing block)的长方形盒子的边进行计算的。通常,生成的盒子作为后代盒子的包含块,也就是说一个盒子产生它后台盒子的包含块。“盒子的包含块”指的是包含盒子的包含块,而不是盒子产生的包含块。
每个盒子都根据它的包含块进行定位,但并不会受包含块限制,它可能溢出(overflow)
2. 控制盒子的生成
下面几节描述了CSS2.1中可能产生的盒子的类型。在视觉格式化模型中,盒子的类型会部分的影响盒子的行为。在CSS2.1中,可以通过"display"属性指定盒子的类型。
2.1 块级元素和块级盒子
块级元素(Block-level element)就是在那些源文档中被格式化成可见的块的元素,比如段落。"display"属性的如下取值将会把元素变成块级元素:"block"、"list-item"和"table"。
块级盒子(Block-level box)就是那些在块格式化上下文(block formatting context)中的盒子。每个块级元素都会产生一个主块级盒子。这个主块级盒子包含后代盒子和其他生成的内容,同时还参与任何的定位策略。有些块级元素,除了主块级盒子以外,还将产生其他的盒子,如"list-item"元素。这些额外的盒子将根据主块级盒子进行布局。
除了表盒子和可替代的元素盒子,块级盒子通常也是块容器盒子(block container box)。一个块容器盒子既可以仅包含块级盒子,又可以建立一个行内格式化上下文,从而包含行级盒子。并不是所有的块容器盒子都是块级盒子,不可替代的行内块以及不可替代的表格单元都是块容器盒子,但他们都不是块级盒子。那些是块容器盒子的块级盒子被叫做块盒子(block box)。
当上下文含义清晰的时候,块级盒子、块容器盒子和块盒子有时被简称为块。
2.2 行级元素和行内盒子
行级元素就是那些源文档中不会导致新块的产生的元素,元素的内容分布在行内。例如段落的强调文字部分、行内图片等。"display"属性的如下属性值指定一个元素为行级元素:"inline"、"inline-table"和"inline-block"。行级元素产生行级盒子,这些行级盒子存在于行内格式化上下文中。
一个行级盒子既表现在它是行级的,又表现在它的内容存在于包含他的行内格式化上下文中。设置了"display:inline"的不可替代元素将会产生一个行盒子。不是行盒子的行级盒子(如可替代的行级元素、行内块元素和行内表格元素)被称为原子行级元素,因为这些盒子在他们的行内格式化上下文中表现为一个单一的不透明盒子。
2.3 "display"属性
"display"属性的取值范围是: inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | none | inherit
"display"属性的初始值为"inline"。
一下是每种取值的具体含义:
  • block 应用该属性值的元素将会产生一个块盒子。
  • inline-block 应用该属性值的元素将产生一个行级块容器。inline-block的内部被格式化成一个块盒子,元素本身被格式化成一个原子行级盒子。
  • inline 应用该属性值的元素将会产生一到多个行盒子。
  • list-item 应用该属性值的元素(比如html中的li)将会产生一个主块级盒子和一个标签盒子。
  • none 应用该属性值的元素将不会出现在格式化结构(formatting structure)中,也就是说,元素不产生任何盒子,对布局没有任何影响。元素的后代元素也不产生盒子,元素和元素的内容被从格式化结构中完全删除。通过设置后代元素的"display"属性值也不能改变。请注意,"display"为"none"时不产生任何不可见的盒子,实际上,根本不产生任何盒子。如果想 产生既不可见又影响格式化结构的盒子,请参考visibility属性。
  • table,inline-table,table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, and table-caption;应用以上属性值的元素将表现得像一个表格元素。
注意,尽管"display"属性的初始值为"inline",但是UA的默认样式表可能覆盖这个值。
以下是一些display属性的例子:
p { display: block } em { display: inline } li { display: list-item } img { display: none }
3. 定位策略(Positioning schemes)
在css 2.1中,一个盒子将经过定位策略来进行定位:
  1. 正常文档流(Normal flow)。 在CSS2.1中,正常文档流包括块级盒子的块格式化上下文,行级盒子的行格式化上下文以及块级盒子和行级盒子的相对定位。
  2. 浮动(Floats)。 在浮动模型中,一个盒子先根据正常文档流定位,然后被从文档流中拿出来尽可能的放到左/右边。上下文中的其他内容将流动到浮动元素的某一边。
  3. 绝对定位(Absolute positioning)。 在绝对定位模型中,盒子被从正常文档流中完全移除(被移除的盒子对它原来的兄弟盒子将不再产生任何影响) 并且根据它的包含块进行定位。
如果一个元素是浮动的、绝对定位的或者是根元素(root element),那么就称这个元素脱离了文档流(out-of-flow)。如果一个元素没有脱离文档流,那么就称这个元素在文档流内(in-flow)。一个脱离文档流的元素A,它的文档流包括元素A本身以及所有A的在文档流内的后代元素。
3.1 position 属性
position属性的取值范围是:static | relative | absolute | fixed | inherit, 初始值为static。每个取值的含义如下:
  • static 应用该属性值的盒子就是正常的盒子,根据正常的文档流来进行定位。top、right、bottom和left属性不生效。
  • relative 应用该属性值的盒子,其位置将根据盒子在正常文档流中初始的位置以及一个偏移量来计算。即盒子的最终位置将相对于原来的位置发生一定的偏移。当盒子B采用相对定位后,盒子B后面的其他盒子的定位将不受影响,就好像盒子B没有采用相对定位一样。
  • absolute 应用该属性值的盒子,其位置由top、right、bottom和left属性来决定,这些属性将根据盒子的包含块来确定偏移量。采用绝对定位的盒子完全脱离正常文档流,也就是说,绝对定位的盒子对其他盒子将不再产生任何影响。采用绝对定位的盒子的外边距(margin)不与其他盒子的外边距重叠(collapse)。
  • fixed 应用该属性值的盒子,其位置将根据绝对定位来计算,另外,盒子还将相对于一定的参照物固定不动。例如在视觉媒体中,采用fixed定位的盒子将相对于视口(viewport)固定不动。
UA可能默认根元素的定位为static定位。
3.2 盒子的偏移: top、right、bottom、left
如果一个元素的position属性值不为static,那么就称这个元素被定位了。被定位的元素将产生被定位的盒子,然后根据如下四个属性进行放置:
top
top属性的取值范围是: 绝对长度值 | 百分比 | auto | inherit, 初始值为auto。
该属性指定一个绝对定位的盒子的外边距上边界(top margin edge)距离这个盒子的包含块的上边界(top edge)的偏移量(距离)。对于采用相对定位的盒子来说,这个偏移量根据盒子本身的上边界计算得出,也就是说,盒子初始采用正常文档流中的位置,然后在那个位置的基础上根据该属性值进行一定的偏移。
right
right属性的取值范围是: 绝对长度值 | 百分比 | auto | inherit ,初始值为auto。
跟top属性一样,该属性指定一个绝对定位的盒子的外边距右边界(right margin edge)距离这个盒子的包含块的右边界(right edge)的偏移量(距离)。对于采用相对定位的盒子来说,这个偏移量根据盒子本身的右边界计算得出。
bottom
botton属性的取值范围是: 绝对长度值 | 百分比 | auto | inherit, 初始值为auto。
跟top属性一样,该属性指定一个绝对定位的盒子的外边距下边界(bottom margin edge)距离这个盒子的包含块的下边界(bottom edge)的偏移量(距离)。对于采用相对定位的盒子来说,这个偏移量根据盒子本身的下边界计算得出。
left
left属性的取值范围是: 绝度长度值 | 百分比 | auto | inherit, 初始值为auto。
跟top属性一样,该属性指定一个绝对定位的盒子的外边距左边界(left margin edge)距离这个盒子的包含块的左边界(left edge)的偏移量(距离)。对于采用相对定位的盒子来说,这个偏移量根据盒子本身的左边界计算得出。
上面这四个属性的具体取值有如下含义:
  • 绝对长度值 相对于参考边的偏移量是个固定的距离且可以为负。
  • 百分比 偏移量是盒子包含块宽度(left、right)或高度(top、bottom)的百分比,可以为负。
  • auto 自动。
4. 正常文档流(Normal flow)
在正常文档流中的盒子都属于一个格式化上下文(formatting context)。这个格式化上下文既可以是块级的,也可以是行级的,但不能两者都是。块级盒子在块格式化上下文(block formatting context)中,行级盒子在行格式化上下文(inline formatting context)中。
4.1 块格式化上下文
浮动的元素、采用绝对定位的元素、不是块盒子的块容器(比如inline-block,table-cell和table-caption)以及设置了overflow且值不为visible(设置了visible的viewport除外)的块盒子将会为他们的内容建立新的块格式化上下文。
在块格式化上下文中,各个盒子从他们的包含块的顶部开始,竖直的顺次放置。相邻的两个盒子的竖直距离有margin属性决定。在同一个格式化上下文中的两个相邻的块级盒子的竖直外边距将会合并。
在块格式化上下文中,每个盒子的左外边界与盒子的包含块的左边界相接(对于从右到左的情况,右外边界与右边界相接)。 即使当有浮动元素存在是也依然使用,除非这个盒子产生了新的块格式化上下文(这样的话,由于浮动,盒子的宽度将变小)。
5.浮动
浮动的盒子会被移动到当前行的左边或者右边。浮动最有趣的特点就是其他内容会在浮动的元素的旁边依次放置(或者通过设置clear属性禁止),或者说其他盒子会流动到浮动盒子的旁边。也就是说,其他盒子将沿着向左浮动的盒子的右边、向右浮动的盒子的左边依次放置。
一个浮动的盒子将会一直向左或向右移动,一直到触碰到包含块的边界或者其他浮动盒子的外边界。如果是行盒子的话,那么浮动盒子的外边界的顶部将与当前行盒子的顶部对其。
如果没有足够的水平空间,那么浮动的盒子将移至下一行直到有足够的空间或者行内已经没有其他浮动元素为止。
因为浮动盒子不在文档流中,所以在浮动盒子前后的未定位的块盒子将像浮动盒子不存在一样的竖直依次放置。但是,浮动盒子所在的当前行以及后面相邻的行盒子都会根据浮动盒子缩短宽度来给浮动盒子留下空间。
如果有个竖直的位置满足如下四个条件: (a)在行盒子的顶部或者顶部之下(b)在行盒子的底部或底部之上(c)在浮动盒子的外边界的顶部或者顶部之下(d)在浮动盒子的外边界的底部或者底部之上,那么行盒子将会换行。也就是说,如果浮动的盒子的外边界高度为0或者为负,那么行盒子不会缩短。
如果缩短的行盒子太短而不能包含任何内容,那么这个行盒子将会换行(并且高度会重新计算)直到有足够的空间或者没有浮动盒子为止。当前行内的任何在浮动盒子之前的盒子都将重新流动到浮动盒子的另一边。换句话说,如果一个行内盒子放在了一个向左浮动盒子的前面,那么,向左浮动的盒子将会放在这一行的开始,与行盒子的顶部对其,之前的行内盒子将会移动到浮动盒子的右边。对于rtl和向右浮动的盒子同理。
table、块级可替换元素或者正常文档流中建立新的块格式化上下文的元素的border盒不能与任何在同一个格式化上下文中的浮动盒子的margin盒重叠。
5.1 float属性
float属性的取值范围是: left | right | none | inherit,初始值为none。
该属性值决定元素向左移动还是向右移,或者根本不动。float属性可以被应用于任何元素上,除了绝对定位的元素。float属性的取值有如下含义:
  • left 元素产生一个向左浮动的块盒子。其他内容流向盒子的右边。
  • right 与left相似,盒子浮动到右边,其他内容流向盒子的左边。
  • none 不浮动
如下9条规定了浮动元素的确切行为:
  1. 向左浮动的盒子的外左边界不能超过包含块的左边界。同理应用于向右浮动的盒子。
  2. 对于一个向左浮动的盒子,如果在这个盒子之前还有其他向左浮动的盒子,那么,这个盒子的左外边界不能超过其他任何向左浮动的盒子的右外边界,或者这个盒子的上边界必须比其他盒子的下边界低。同理应用于向右浮动的盒子。
  3. 任何向左浮动的盒子的右外边界不能超过任何与之相邻的向右浮动的盒子的左外边界。同理应用于向右浮动的盒子。
  4. 浮动盒子的上外边界不能比包含块的上边界高。当浮动发生在两个合并的margin中时,浮动的盒子根据一个假设的父的空匿名块盒子定位。
  5. 浮动盒子的上外边界不能比任何其他之前的块盒子或浮动盒子的上外边界高。
  6. 浮动盒子的上外边界不能比任何之前的行盒子的上边界高。
  7. 一个向左浮动的盒子,如果在他之前还有向左浮动的盒子,那么这个盒子的右外边界不能超过包含块的有边界,除非这个盒子已经尽可能的向左了。同理应用于向右浮动的盒子。
  8. 浮动元素要尽可能的往高放置。
  9. 向左浮动的盒子要尽可能向左,向右浮动的盒子要尽可能向右。但是相对于尽可能向左或向右,更高的位置有更高的优先级。
下面的html片段,b浮动到右边:
<P>a<SPAN style="float: right">b</SPAN></P>
如果P元素的宽度足够,那么a和b将各占一边,如下:
5.2 clear属性
clear属性的取值范围是: none | left | right | both | inherit, 初始值为none。只应用于块级元素。
该属性决定元素盒子的哪一边不与浮动盒子相邻。clear属性不考虑被应用元素内部的浮动以及其他块格式化上下文中的浮动。
属性取值含义如下:
  • left 应用该属性值的元素盒子的上边界要低于该元素之前的左浮动元素盒子的底外边界。
  • right 应用该属性值的元素盒子的上边界要低于该元素之前的右浮动元素盒子的底外边界。
  • both 应用该属性值的元素盒子的上边界要低于该元素之前的左浮动或右浮动元素盒子的底外边界。
  • none 不浮动。
所有不是none的值都将引入空隙(clearance)。clearance禁止margin合并,表现得就像元素的上外边距外还有一段空间。
要计算应用了clear属性的元素的clearance,首先需要找到元素上边界的假定位置。这个假定位置就是当clear属性值为none时元素实际上的上边界。
如果假定的元素的上边界不能越过相关的浮动元素(past the relevant floats),那么就需要引入clearance。
空隙的大小为如下两个值中的较大值:
  1. 将元素的上边界与最低的浮动元素的底外边界对齐需要的空间大小。
  2. 将元素的上边界放置到它假定的位置需要的空间大小。
注意,空隙的大小可能为负也可能为0.
6.display、position和float的关系
这三个属性都影响盒子的产生以及定位,他们关系如下:
  1. 如果display的值为none,那么position和float不起作用。在这种情况下,元素不产生盒子。
  2. 否则,如果position的值为absolute或者fixed,那么盒子就使用绝对定位,float的最终使用的值为none,display的取值依据如下表格来定。盒子的显示位置根据top、right、bottom和left属性决定。
  3. 否则,如果float的取值不会none,那么盒子将会浮动,display的取值参照下表。
  4. 否则,如果元素是根元素,那么display的取值参照下表。
  5. 否则,display的取值就是指定的值。
  6. 指定的值 最终使用的值
    inline-table table
    inline, table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, table-caption, inline-block

    block

    其他

    与指定的值相同