[CSS 2.2 中文] 可视化格式模型 - Visual Formatting Model

CSS 标准翻译

Posted by Nicodechal on 2019-10-16

LINK

可视化格式模型 ( Visual Formatting Model ) 序言

这一章 (第九章) 和下一章将描述可视化格式模型 ( visual formatting model ),即用户代理 ( user agents ) 如何为可视媒体 ( visual media ) 处理文档树 ( document tree )。

在可视化格式模型中,文档树中的每个元素都会根据盒子模型 ( box model ) 生成零个或多个盒子 (box)。这些盒子的布局取决于下面几点:

  1. 盒子尺寸 和 类型 ( box dimensions and type )
  2. 定位方式 ( positioning schemes ),常规流,浮动和绝对定位 ( normal flow, float, and absolute positioning )。
  3. 文档树中元素之间的关系
  4. 外部信息 (例如,视口大小,图片本身的尺寸等)

本章和下一章中定义的属性适用于连续媒体和分页媒体 ( continuous media and paged media )。 但是,外边距 ( margin ) 属性的含义在应用于分页媒体时会有所不同 ( 有关详细信息,请参见页面模型 (page model) )。

可视化格式模型并未指定格式化的所有方面(例如,未指定字母间距算法)。 对于本规范未涵盖的格式化问题,一致的用户代理的在这些方面的行为可能有所不同。

视口 ( The Viewport )

连续媒体的用户代理通常会提供一个 “视口” 给用户 ( 一个窗口或者屏幕上的一个浏览区域 ) 用来查看文档。用户代理可能会在视口大小变化时改变文档的布局。( 见 初始包含块 )

包含块 ( Containing Blocks )

在 CSS 2.2 中,许多盒的位置和尺寸都相对于一个矩形盒子的边缘进行计算,这个矩形盒叫做包含块 ( containing blocks )。通常,已经生成的盒是其后代盒的包含块;这里我们说一个盒子为它的后代盒子 “建立” ( “establishes” ) 了包含块。习惯的说法 “一个盒子的包含块” 指的是 “这个盒子所在的包含块” 而不是这个盒子生成的包含块。

每个盒子都根据其包含块确定位置,但是盒子不会被包含块限制 ( confined );它有可能会溢出 ( overflow ) 。

下一章会说明包含块尺寸的计算细节。

控制盒子的生成

以下各节描述了 CSS 2.2 中可能生成的盒类型。盒类型部分地影响盒在可视化格式模型中的行为。下面描述的 display 属性指定了盒的盒类型。

display 属性的某些值会使得源文档的元素生成一个主盒 ( principal box ) ,主盒包含后代盒子和其所生成的内容,主盒也是进行定位 ( positioning scheme ) 时会用到的盒子。 除主盒外,某些元素还可能生成其他盒,比如 list-item 元素。 这些其他盒会相对于主盒进行放置。

块级元素和块盒 ( Block-level elements and block boxes )

块级元素 ( block-level elements ) - 源文档中可视格式化后是块的元素 ( 例如,段落元素 ),这些元素会生成一个块级的主盒 ( block-level principal box ) 。设置 display 属性为下面值之一可以使一个元素变为块级元素:blocklist-itemtable块级盒 ( block-level boxes,译者注:这里应该就是块级元素生成的主盒 ) 将会参与块格式化上下文 ( BFC, block formatting context )

在 CSS 2.2 中,一个块级盒一般也是一个块容器盒 ( block container box ), 除非这个块级盒是一个表格盒 ( table box ) 或者一个替换元素 ( replaced element ) 的主盒。块容器盒 要么只包含块级盒,要么建立一个行内格式化上下文 ( IFC, inline formatting context ),此时这个块容器盒只包含行内级盒 ( inline-level boxes )。

如果一个元素的主盒是一个块容器盒,这个元素称为块容器元素 ( block container element )。下面的 display 值使一个非替换元素 ( non-replaced element ) 生成一个块盒:blocklist-iteminline-block

并非所有的块容器盒都是块级盒:非替换行内块 ( non-replaced inline blocks ) 和非替换表格单元格 ( non-replaced table cell ) 都是块容器盒但不是块级盒。如果一个盒既是块级盒又是块容器盒则被称为块盒 ( block boxes )。

在不会有歧义的时候,块级盒,块容器盒和块盒有时会简写为 ( block )。

匿名块盒 ( Anonymous block boxes )

在如下的文档中:

1
2
3
4
<DIV>
Some text
<P>More text
</DIV>

( 这里假设 DIV 和 P 都有属性 display: block ),DIV 同时拥有了行内内容 ( inline content ) 和块内容 ( block content )。为了方便定义格式化方式,我们假设有一个匿名块盒环绕着 “Some text”。

Diagram showing the three boxes, of which one is anonymous, for the example above.

换句话说,如果一个块容器盒 ( 例如上面 DIV 生成的盒 ) 里有一个块级盒 ( 例如上面的 P ) ,那我们强制这个块容器盒里只有块级盒。

当一个行内盒 ( inline box, 下面定义) 包含一个在流中 ( in-flow ) 的块级盒时,这个行内盒 ( 以及在同一个行盒 ( line box ) 中的行内祖先 ( inline ancestors ) ) 会在这个块级盒 ( 以及所有 连续的 或者 只由可折叠的空白字符和 ( 或者 ) 不在流上 ( out-of-flow ) 的元素分隔 的块级兄弟 ) 两侧拆分,将这和行内盒分为两个盒 ( 即使某一侧是空的 ),分布在块级盒的两侧。拆分之后的两个行盒由匿名块盒包裹,块级盒成为这两个匿名块的兄弟。当行盒受到相对定位 ( relative positioning ) 影响时,产生的结果也会影响其包含的块级盒。

当下面的规则被用在下面的 HTML 文档中时,上述模型会被应用:
1
2
p    { display: inline }
span { display: block }
1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HEAD>
<TITLE>Anonymous text interrupted by a block</TITLE>
</HEAD>
<BODY>
<P>
This is anonymous text before the SPAN.
<SPAN>This is the content of SPAN.</SPAN>
This is anonymous text after the SPAN.
</P>
</BODY>

P 元素包含一个匿名文本块 ( C1 ),紧接着是一个块级元素再紧接着是两一个匿名文本块 ( C2 )。产生的结果盒会是一个表示 BODY 的块盒,包含一个包裹 C1 匿名块盒、SPAN 块盒和另一个包裹 C2 的匿名块盒。

匿名块的属性从包裹它的非匿名块继承 ( 对于小节 “匿名块盒” 下的例子,就是 DIV)。非继承属性拥有它们的初始值 ( inital value )。例如,匿名块的 font 从 DIV 继承,单是 margin 将会是 0。

设置在发生匿名块盒生成的元素上的属性仍旧会应用在元素的盒子以及元素的内容上。例如在上面的例子上为 P 设置边框,那么边框会画在 C1 ( 在结尾不闭合 ) 和 C2 ( 在开头不闭合 ) 上。

有些用户代理用其他方式实现包含块盒的行内盒的边框。例如,把其中嵌套的块盒包裹在一个匿名行盒 ( anonymous line boxes ) 中, 因此会在块盒周围绘制行内元素的边框。由于 CSS1 和 CSS2 没有定义这种行为,所以 CSS1-only 和 CSS2-only 的用户代理可能会实现这个替代模型并仍旧声称对于 CSS2.2 的这一部分一致。这并不适用于那些在本规范已经放出之后开发的用户代理。

匿名块在解析百分比值需要引用它时被忽略:最近的非匿名祖先块被用来进行引用。例如,在匿名块 ( 上面例子中 DIV 中的那个 ) 中的孩子需要他的包含块 ( containing block ) 的高度来解析一个百分比值得高度,那么他就需要使用由 DIV 形成的包含块的高度,而不是匿名块的高度。

行内级元素和行内盒 ( Inline-level elements and inline boxes )

行内级元素 ( inline-level elements ) 是源文档中其内容不会形成新块盒 ( blocks ) 的元素;其内容分布在多个行中 ( 例如,一个段落中强调的部分,行内图片等等 ) 。下面这些 display 值使得一个元素变为行内级:inlineinline-tableinline-block。行内级元素生成行内级盒 ( inline-level boxes ),这些盒子参与行内格式化上下文 ( inline formatting context )。

一个行内盒 ( inline boxes ) 首先是一个行内级盒,且其包含的内容参与行内盒所在的行内格式化上下文 ( An inline box is one that is both inline-level and whose contents participate in its containing inline formatting context. )。一个非替换元素的 display 属性值为 inline 时生成一个行内盒。是行内级盒但不是行内盒的元素称为原子行内级盒 ( atomic inline-level boxes ),因为他们在他们的行内格式化上下文中类似于一个不透明的盒子 ( single opaque box ) 。(译者注:Opaque means that the box is a singular, solid unit, and that it cannot be split across lines like an inline box can when its text cannot all fit on a single line.)

匿名行内盒 ( Anonymous inline boxes )

任何直接包含在一个块容器元素中的文本 ( 即不在行内元素内 ) 必需被看做一个匿名行内盒

在下面的 HTML 文档中:

1
<p>Some <em>emphasized</em> text</p>

<p> 元素生成了一个块盒,其中包含了一些行内盒。“emphasized” 的盒由行内元素 <em> 生成,但是其他的盒子 ( “Some” 和 “text” ) 是由块级盒 ( <p> ) 生成的行内盒,它们叫做匿名行内盒,因为它们没有想算的行内级元素。

此类匿名行内盒从其块父亲块盒继承可继承的属性。非继承属性具有其初始值。在上面的例子中,匿名行内盒的 color 继承自 P,但是它的 background 是透明的。

之后,根据 white-space 属性折叠起来的空白不会生成任何匿名行内盒。

如果从上下文中可以清楚地知道是哪种类型的匿名盒,则在本规范中,匿名行内盒和匿名块盒都简称为匿名盒。

格式化表格时,会出现更多类型的匿名盒。

Run-in boxes

[存在此部分,使编号与以前的草案中的相同。 现在,在CSS级别3中定义了display: run-in ( 请参阅 CSS基本框模型 )。

display 属性

表格参见文档。属性取值的含义如下:

block
该值是一个元素生成一个主块盒 ( principal block box ).

inline-block
该值使得一个元素生成一个主要的行内级块容器 ( principal inline-level block container )。( inline-block 内部格式化为一个块盒,而该元素本身格式化为一个原子行内级盒 )。

inline
该值使得一个元素生成一个或多个行内盒。

list-item
该值使得一个元素 ( 例如 HTML 中的 LI )生成一个主要的块盒以及一个标记盒 ( marker box )。关于列表和列表的格式化的信息,参阅列表一节。

none
该值使得元素不在格式化结构 ( formatting structure ) 中出现 ( 即在可视化媒体中,元素不产生任何盒子因此对布局没有影响 )。后代元素也不生成任何盒。元素及其内容将从格式化结构中完全删除,在子孙元素上设置’display’属性,不能覆盖此行为。

请注意,displaynone 不会创建不可见的盒;它根本不会创建任何盒子。CSS 有使元素能够在格式化结构中生成影响格式但本身不可见的盒的机制。有关详细信息,请查阅可见性部分。

table, inline-table, table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, and table-caption
这些值使元素的行为类似于表元素 ( 因此会受章节所述内容的限制 )。

计算值和具体设置的值一样,除了定位元素、浮动元素 ( 见 displaypositionfloat 的关系 一节,在下方 ) 和根元素。对于根节点,其计算值会被改变,具体在 displaypositionfloat 的关系 小节描述。

注意尽管初始值是 inline,但用户代理的默认层叠样式可能会覆盖这个值,见附录中 HTML4 样例层叠样式。

以下是一些 display 属性的例子:

1
2
3
4
p   { display: block }
em { display: inline }
li { display: list-item }
img { display: none } /* Do not display images */

定位方式 ( Positioning schemes )

在 CSS 2.2 中,一个盒子根据三种定位方式进行布局:

  1. 常规流 ( Normal flow ) 。常规流包含块级盒的块格式化和行内级盒的行内格式化,以及块级盒和行内级盒的相对定位。
  2. 浮动 ( Floats ) 。在浮动模型中,一个盒首先根据常规流进行布局,然后从流中取出并尽可能的向左或向右移动。内容流可能会在浮动元素周围。
  3. 绝对定位 ( Absolute positioning )。 在绝对定位模型中,一个盒完全从常规流中取出 ( 它对后续兄弟节点无影响 ) 然后相对于其包含块赋予一个位置。

如果一个元素是浮动的、绝对定位的或者根元素,那我们称这个元素在流外 ( out-of-flow ),一个元素在流内 ( in-flow ) 如果它不在流外。一个元素 A 的流 ( flow of an element A ) 是一个包含 A 和所有在流内的并且最近的流外祖先为 A 的元素

**注意。**CSS 2.2的定位方式可帮助作者避免用于布局效果的标记技巧(例如,不可见的图像),从而使文档更易于访问。

选择一个定位方式:position 属性

positionfloat 属性决定了 CSS 2.2 中那种定位算法被用来计算一个盒子的位置。

表格参见文档。属性取值的含义如下:

static
一个盒为常规盒,根据常规流布局,toprightbottomleft 不生效。

relative
盒子的位置根据常规流进行计算 ( 这被称为常规流中的位置 ) 。接着盒子相对于自己的常规位置进行相对偏移。如果一个盒 B 是相对定位的,其后续的盒子计算位置时当做 B 没有偏移。position:relative 在 table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, and table-caption 元素上未定义。

absolute
盒子的位置 ( 也可能有尺寸 ) 由 toprightbottomleft 属性确定。这些属性确定盒子相对于其包含块的偏移。绝对地定位的盒子会从常规流中取出。这意味着它不影响后续兄弟节点的布局。同时,尽管绝对地定位的盒子有外边距,但他们不和任何其他外边距折叠 ( collapse ) 。

fixed
盒子的位置根据 absolute 模式计算得出,但是另外,盒子相对于某些引用 ( reference ) 是固定的。 与 absolute 模式一样,盒的外边距不会与其他任何外边距折叠。 对于手持设备,投影,屏幕,tty 和电视媒体类型,该盒子相对于视口是固定的,滚动时不会移动。 在打印介质类型的情况下,即使通过视口查看页面 ( 例如,在打印预览的情况下 ),该盒子也会在每个页面上呈现,并且相对于页面盒 ( page box ) 是固定的。对于其他媒体类型,显示效果是未定义的。有些人可能希望针对不同媒体指定 fixed 例如,作者可能希望将一个盒子保持在屏幕上视口的顶部,但不在每个打印页面的顶部出现。此时可以使用 @media 规则将两个规范分开,如下所示:

1
2
3
4
5
6
@media screen { 
h1#first { position: fixed }
}
@media print {
h1#first { position: static }
}

用户代理不能为 fixed 的盒子添加页码。注意用户代理可能会用其他方式打印不可见的内容。见第 13 章的 “Content outside the page box”

盒子偏移:toprightbottomleft

一个元素的 position 如果不是 static 则称其被定位了 ( positioned ) 。定位元素 ( positioned elements ) 生成定位盒 ( positioned boxes ) ,根据下面 4 个属性布局:

表格参见文档: top

该属性指定了一个绝对地定位盒的上外边距边缘相对于其包含块的上边缘的偏移。对于相对定位盒,这个偏移相对于自己的上边缘 ( 即,这个盒子有一个常规流中的位置,然后根据这个属性从那个位置进行偏移 ) 。

表格参见文档: right

top 相似,不过这里指定盒子的右外边缘相对于其包含块右边缘向左偏移多远。对于相对定位盒,这个偏移相对于自己的右边缘。

表格参见文档: bottom

top 相似,不过这里指定盒子的下外边缘相对于其包含块下边缘向上偏移多远。对于相对定位盒,这个偏移相对于自己的下边缘。

表格参见文档: left

top 相似,不过这里指定盒子的左外边缘相对于其包含块左边缘向右偏移多远。对于相对定位盒,这个偏移相对于自己的左边缘。

四个属性取值的含义如下:

<length>
相对参考的边缘偏移一个固定距离。负值也可以。

<percentage>
相对参考的边缘偏移是一个相对于包含块宽度 ( leftright ) 或高度 ( topbottom ) 的百分比。负值也可以。

auto
对于非替换元素,该值的效果取决于哪一个相关的属性值也为 auto。见绝对地定位中的非替换元素的宽度高度。对于替换元素,该值只取决于替换内容本身的尺寸,见绝对地定位中的替换元素的宽度和高度。

常规流 ( Normal flow )

常规流中的盒子都属于一个格式化上下文,在 CSS 2.2 中这个上下文可能是 表格上下文,块上下文和行内上下文。在之后的 CSS 中,其他的格式化上下文会被介绍。块级盒参与一个块格式化上下文。行内级盒参与一个行格式化上下文。表格上下文在表格章节进行描述。

块格式化上下文

不是块盒的比如:浮动元素、绝对地定位元素和块容器盒 ( 比如 inline-blocktable-cellstable-caption),以及且具有不是 visibleoverflow 属性的块盒 ( 除非当这个值被传播到了视口 ( 译者注:可能是指body元素 ) ),会为他们的内容建立一个新的块格式化上下文。

在一个块格式化上下文中,盒子垂直地一个接一个的进行布局,从包含块的开始处开始布局。两个兄弟盒子之间的垂直距离取决于他们的 margin 属性。一个块格式化上下文中的相邻的块级盒的垂直外边距和发生折叠 ( collapse )。

在块格式化上下文中,每一个盒子的左外边缘接触包含块的左边缘 ( 对于从右到左的格式化,接触右边缘 )。这一条即便是有浮动元素参与也成立 ( 尽管这时相关盒子的行盒可能会由于浮动变窄 ),除非相关盒子建立了一个新的块格式化上下文 ( 此时这个盒子本身会因为浮动变得更窄 )。

对于分页媒体的页面分割,请查阅相关小节允许的页面分割

行内格式化上下文

行内格式化上下文由一个不包含块级盒的块容器盒建立。在一个行内格式化上下文中,盒子们水平的进行布局,从包含块的开始处一个接一个布局。盒子之间有水平方向的外边距、边框和内边距。盒子们在垂直方向上以不同的方式对齐:他们的底部或顶部可能会被对齐,或者他们内部的文本的 baseline 会被对齐。一个包含的盒子形成一条线的矩形区域称为行盒 ( line box )。

行盒的宽度由包含块和浮动的参与决定。行盒的高度由行高的计算一节中的规则决定。

行盒的高度总是足够包含其中的盒子们。但是,它有可能会比其包含的盒子中最高的盒子还要高 ( 例如,如果盒子们通过对齐使得 baseline 上移 )。当一个盒子 B 的高度小于包含它的行盒的高度,B 垂直方向上的对齐由 vertical-align 决定。当多个行级盒不能水平的放进一个行盒时,它们会分布在两个或更多的垂直方向以栈的方式堆叠的 ( vertically-stacked ) 行盒中。因此,一个段落就是一个行盒的垂直栈。行盒在垂直方向上堆叠且没有垂直方向的分隔 ( 除非在其他地方指定 ),并且它们从来不会重叠。

通常,行盒的左边缘接触其包含块的左边缘。然而浮动盒可能会出现在它们之间。因此,尽管通常在同一个行内格式化上下文中的行盒都有相同的宽度 ( 在包含块中 ),但它们的宽度在水平空间由于浮动元素减少时也有可能变化。在同一个行内格式化上下文中的行盒通常高度不同 ( 例如,一行可能有一张很高的图片,另一行只包含文本 )。

当一行中的行内级盒的整体的宽度比包含它们的行盒的宽度小时,他们在行盒中的水平分布取决于 text-align 属性。如果这个属性值为 justify,那么用户代理还应该会扩大行内盒中的空格和单词 ( 在 inline-tableinline-block 中不会 )。

如果一个行内盒的宽度超过了行盒的宽度,他们会分为多个盒子然后这些盒子会分布在多个行盒中。如果一个行盒不能被分割 ( 例如:如果行内盒包含一个字符,或者特定语言的分割规则不允许行内盒的分割,又或者行内盒受到 white-space 值为 nowarp 或者 pre 的影响 ),那么行内盒会溢出行盒。

如果一个行内盒被分割,外边距、边框和内边距不会在分割处有可视化的影响 ( 在所有的分割处都是如此 )。

行内盒可能会在同一个行盒中被分割为数个盒子,这是由于双向文字处理( bidirectional text processing )。

行盒在需要控制行内格式化上下文中的行内级内容时被创建。一个行盒如果没有文本,没有保留的空白符,没有外边距、内边距或边框不为零的行内元素,没有其他在流中的内容 ( 比如图像、行内块或行内表 ),并且没有以一个保留的新行结束,那么这个行盒要被看作是一个用于确定其内部元素位置的高度为零的行盒,对于其他情况,要看做它不存在。

下面是一个构造行内盒的例子。下面段落 ( 由 HTML 块级元素 P 创建 ) 包含匿名文本和 EM 元素 STRONG 元素。
1
2
<P>Several <EM>emphasized words</EM> appear
<STRONG>in this</STRONG> sentence, dear.</P>

这个 P 元素创造了一个块盒包含五个行内盒,有三个是匿名的:

  • 匿名盒: “Several”
  • EM: “emphasized words”
  • 匿名盒: “appear”
  • STRONG: “in this”
  • 匿名盒: “sentence, dear.”

为了格式化这个段落,用户代理把这五个元素放入行盒中。在这个例子中,P 元素的盒子建立了行盒的包含块。如果包含块够宽,所有的行盒会放进一个行盒中:

Several emphasized words appear in this sentence, dear.

如果不是,行内盒会被分割然后分布在几个行盒中。之前的段落可能像这样分割:

Several emphasized words appear
in this sentence, dear.

或这样:

Several emphasized
words
appear
in this sentence, dear.

上面例子中,EM 盒被分成了两个 EM 盒 ( 称为 split1 和 split2 )。外边距,边框,内边距或者文本装饰不会在 split1 后和 split2 前有视觉影响。

考虑下面例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
<HEAD>
<TITLE>Example of inline flow on several lines</TITLE>
<STYLE type="text/css">
EM {
padding: 2px;
margin: 1em;
border-width: medium;
border-style: dashed;
line-height: 2.4em;
}
</STYLE>
</HEAD>
<BODY>
<P>Several <EM>emphasized words</EM> appear here.</P>
</BODY>
</HTML>

取决于 P 的宽度,盒子们可能会像下面这样分布:

  • 外边距在 “emphasized” 的前面和 “words” 的后面插入。
  • 内边距在 “emphasized” 的上下、前面和 “words” 的上下、后面插入。一个点划线的边框在每个部分的三面渲染。

相对定位

一旦一个盒子根据常规流或浮动布局后,它可能会相对于这个位置进行移动。这称为相对定位 ( relative positioning ) 。以这样的方式偏移一个盒子 ( B1 ),不会对后续的盒子 ( B2 ) 产生影响:B2 的位置假设 B1 没有偏移给出并且在 B1 偏移后 B2 也不会重新定位。这暗示了相对定位可能会使盒子重叠。然而,如果相对定位导致了一个 overflow: auto 或者 overflow: scroll 的盒子溢出,用户代理必需使用户可以访问到这些内容,尽管这样会导致滚动条的创建,进而影响布局。

一个相对定位的盒子保持它在常规流中的尺寸,包括断行和原来为其保留的空白。包含块一节解释了什么时候一个相对定位的盒子会建立一个新的包含块。

对于相对布局的元素,leftright 水平地移动盒子,不会改变其尺寸。left 将盒子向右移动,right 将盒子向左移动。由于盒子不会由于 leftright 被分割或拉长,所以被使用的值一直是 left = -right

如果 leftright 都是 auto ( 即初始值 ),使用值为 0 ( 即,盒子保持在它原来的位置 )。

如果 leftauto,其使用值为 right 的负值 ( 即,盒子根据 right 值向左移动 )。

如果 right 值为 auto,其使用值为 left 的负值。

如果 leftright 都不是 auto,其位置被过度约束了 ( over-constrained ),因此其中一个会被忽略。如果包含块 direction 属性为 ltrleft 值胜出 right 值变为 -left。如果 direction 属性为 rtlright 值胜出 left 值被忽略。

例子。下面三条规则是等价的:
1
2
3
div.a8 { position: relative; direction: ltr; left: -1em; right: auto }
div.a8 { position: relative; direction: ltr; left: auto; right: 1em }
div.a8 { position: relative; direction: ltr; left: -1em; right: 5em }
`top` 和 `bottom` 上下地移动盒子,不会改变其尺寸。`top` 将盒子向下移动,`bottom` 将盒子向上移动。由于盒子不会由于 `top` 和 `bottom` 被分割或拉长,所以被使用的值一直是 `top = -bottom`。如果两者都是 `auto`,他们的使用值都是 `0`。如果其中一个是 `auto`,它的值变为另一个的负值。如果都不是,`bottom` 会被忽略。

注释:动态的移动相对定位的元素可以在脚本环境下产生动画效果 ( 又见 visibility 属性 )。尽管相对定位可能会用来形成上标或下标,但其行高不会考虑相对定位自动的调整。更多信息见行高的计算一节。

相对定位的例子在 常规流、浮动盒绝对定位的比较 一节提供。

浮动 ( Floats )

浮动盒是被移动到当前行左边或右边的盒子。一个浮动盒 ( 或者 “浮动” ( floating ) 、“浮动的” ( floated ) 盒子 ) 最有趣的特征是内容 ( content ) 可能会在其两侧流动 ( flow ) ( 或者由于 clear 被禁止 )。内容在一个向左浮动的盒子右侧出现,在一个向左浮动的盒子右侧出现。下面是关于浮动定位和内容流 ( content flow ) 的导言;决定浮动行为的具体的规则在 float 属性的描述部分给出。

一个浮动盒会向左或向右浮动直到其外边缘接触到其包含块的边缘或者两一个浮动元素的外边缘。如果此时有一个行盒,浮动盒的外上边缘会和当前行盒的上边缘对齐。

如果没有足够的水平空间用于浮动,它会向下移动直到其可以放下或没有其他的浮动出现。

由于一个浮动盒不在流上,在浮动盒前后的没有被定位的盒子在垂直方向上流动 ( flow ) 好像浮动盒不存在。然而,紧挨着 (next to) 浮动元素创建的当前和后续的行盒为了给浮动盒的外边距盒腾出空间会变短。

一个行盒紧接着 (next to) 一个浮动元素当存在一个垂直位置满足下面四个条件:(a) 在行盒的顶部或顶部的下面,(b) 在行盒的底部或底部的上面,© 在浮动盒子上外边距的下面和 (d) 在浮动盒下外边距的上面。(译者注:紧挨着就是并排)

注释:这意味着零高度或者负高度的浮动盒不会使行盒缩短。

如果一个变短的行盒太小了以致于不能容纳任何内容,那么这个行盒会向下移动 ( 同时它的宽度也会重新计算 ) 直到有内容可以放入或没有其他浮动出现。在当前行的任何在浮动盒前面的内容都会重新流动到浮动盒的另一侧。换句话说,如果一个行内级盒放置在和浮动盒同一行中的在浮动盒之前,且可以放进行盒剩余的空间,那么这个左浮动盒就放置在这一行,和行盒的顶部对齐,然后本来在这一行的行内级盒因此会移动到浮动盒的右边 ( 左浮动盒的另一侧就是右侧 ),对于 rtl 和右浮动亦然。

table、块级替换元素或者常规流中建立块格式化上下文的元素 ( 例如一个 overflow 不是 visible 的元素 ) 的边框盒不能和同一个块上下文中的任何浮动元素的外边框盒重叠。如果有必要,实现需要通过把这个元素放在其前面的浮动元素的下面来清除 ( clear ) 这个元素,但如果有足够的空间,也有可能紧邻着这个浮动元素。这甚至可能使得这个元素的边框盒比 10.3.3 小节描述的更窄。CSS2 未定义什么时候需要把这个元素紧挨着 ( next to ) 浮动元素以及元素可能会变窄多少。

例子。在下面的文档片段中,包含块太窄所以不能容纳紧挨着浮动盒的内容,所以内容移到了浮动盒的下方同时根据 `text-align` 属性在行盒中对齐。
1
2
3
4
5
6
7
8
9
p { width: 10em; border: solid aqua; }
span { float: left; width: 5em; height: 5em; border: solid blue; }

...

<p>
<span> </span>
Supercalifragilisticexpialidocious
</p>

看起来会像下面这样:

多个浮动盒可能会相接,此时这个模型也会对同一行的浮动盒应用。

下面的例子使所有 `class=icon` 的 IMG 盒向左浮动 ( 同时左边距为 ‘0’ )
1
2
3
4
img.icon { 
float: left;
margin-left: 0;
}
考虑下面的 HTML 源文件和样式表:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
<HEAD>
<TITLE>Float example</TITLE>
<STYLE type="text/css">
IMG { float: left }
BODY, P, IMG { margin: 2em }
</STYLE>
</HEAD>
<BODY>
<P><IMG src=img.png alt="This image will illustrate floats">
Some sample text that has no other...
</BODY>
</HTML>

IMG 向左浮动。随后的内容被格式化到了浮动的右边,和浮动盒一样的行开始。浮动盒右边的行盒由于浮动的出现变短,在浮动盒之后又还原为正常宽度 ( 由 P 元素建立的包含块 )。这个文档可能会格式化为下面:

下面文档格式化后和上面一样:

1
2
3
4
5
<BODY>
<P>Some sample text
<IMG src=img.png alt="This image will illustrate floats">
that has no other...
</BODY>

因为浮动盒左侧的内容会被浮动盒替换并且移动到浮动盒的右侧。

就像在 8.3.1 小节开始说的,浮动盒的外边距不会和相接的盒子的外边距折叠。因此,在之前的例子中,P 和 IMG 的垂直外边距没有发生折叠。

浮动盒的内容会被堆叠 ( stacked ) 起来好像浮动盒生成了新的层叠上下文 ( stacking contexts ),除非有定位元素和产生了新的层叠上下文的元素参与了浮动盒的双亲层叠上下文。一个浮动盒可以和其他常规流中的盒子重叠 ( 例如,当一个紧挨着浮动盒的常规流盒子有负外边距 )。此时,浮动元素在非定位流内块 ( non-positioned in-flow blocks ) 之前渲染,在流内行内块 ( in-flow inlines ) 后渲染。

这是另一个例子,展示了浮动盒和常规流中的元素边框的重叠。

下面例子说明使用 clear 元素阻止内容紧挨着浮动盒。

假设有下面规则:
1
p { clear: left }

格式化如下:

定位浮动: float 属性

表格参见文档

该属性指明一个盒子时候向左浮动、向右浮动或者不浮动。该属性可以为任何元素设置,但只会应用在生成的盒子不是绝对地定位的元素上。属性取值的含义如下:

left
元素生成一个块盒向左浮动。内容在盒子的右边流动,从盒子的上部开始。

right
left 类似,除了元素生成一个块盒向右浮动。内容在盒子的左边流动,从盒子的上部开始。

none
盒子不浮动。

用户代理可能会认为根元素的 floatnone

下面是控制浮动行为的精确规则:

  1. 左浮动盒的左外边缘不会到其包含块左边缘的左边。右浮动盒规则相似。
  2. 如果当前盒子是左浮动的,如果有在源文档中生成更早的元素的盒子,那么对于每一个更早的盒子,当前盒的左外边缘必须在之前盒的右边缘的右边,或者其顶部必需比之前盒的顶部低。右浮动盒规则相似。
  3. 左浮动盒的右外边距可能不会到紧挨着它的右浮动盒左外边距的右边。右浮动盒规则相似。
  4. 浮动盒的顶外边距不会比包含块的顶部高。当浮动出现在两个折叠的外边距之间时,浮动盒子像有一个其他的空匿名父亲盒参与在流中一样定位。这个父亲的定位规则根据外边距折叠一节规则给出。
  5. 浮动盒的上外边缘可能不会比任何源文档中生成更早的块或浮动盒的上外边缘高。
  6. 一个元素的浮动盒的上外边缘不会比包含源文档中更早生成的元素的行盒的顶部高。
  7. 一个向左浮动的盒子如果有另一个向左浮动的盒子在它的左边,那么它的右外边缘不会到达其包含块的右边缘的右边。( 松散的:一个左浮动盒不会伸出 ( stick out ) 到包含块的右边缘,除非它已经足够靠左了 )。
  8. 一个浮动盒子必须尽可能高的放置。
  9. 一个左浮动盒必须尽可能向左放置,一个右浮动盒必须尽可能向右放置,相比于左右的位置,更偏向更高的位置。

但是在 CSS 2.2 中,如果在一个块格式化上下文中,有一个在流中的负垂直外边距导致浮动位置在其原位置 ( 假设其负外边距设置为 0 ) 之上,浮动的位置是未定义的。

本规则中引用的其他元素只会引用和浮动元素块格式化上下文相同的元素。

这是 b 向右浮动的结果。
1
<P>a<SPAN style="float: right">b</SPAN></P>

如果 P 的宽度足够大,a 和 b 会一人一边。看起来像这样:

控制 紧挨着 ( next to ) 浮动盒的流:clear 属性

表格参见文档

该属性说明一个元素的盒子们哪一侧不会和之前的浮动盒相邻。clear 属性不考虑元素内部其他块格式化上下文中的元素。

当应用到非浮动块级盒时取值含义的含义如下:

left
需要盒子的上边框边缘在文档树中更早出现的元素产生的左浮动盒的下外边缘的下面。

right
需要盒子的上边框边缘在文档树中更早出现的元素产生的右浮动盒的下外边缘的下面。

both
需要盒子的上边框边缘在文档树中更早出现的元素产生的浮动盒的下外边缘的下面。

none
关于浮动,不限制盒子的位置。

none 的取值可能会产生间隙 ( clearance )。间隙禁止外边距折叠,作为元素的上外边距上方存在。它用来在垂直方向上将元素向下推使其越过浮动盒。

计算设置了 clear 的元素的间隙首先需要决定元素的上边框边缘的假设位置。这个位置就是当 clearnone 时的上边框边缘的位置。

如果元素上边框边缘的假设位置没有越过相关的浮动盒,那么间隙就会出现,同时外边距折叠根据 8.3.1 中的规则进行。

接着间隙的大小 ( amount ) 设为下面较大的一个:

  1. 使得 clear 的块的边框边缘放置在最低的浮动盒的下外边缘的大小。
  2. 使得 clear 的块上边框边缘在其假设位置的大小。

或者说,间隙恰恰使得 clear 的块的边框边缘放置在最低的浮动盒的下外边缘。

注意:两种行为都允许其兼容性对存在的 Web 内容等待评估。未来的 CSS 标准将会要求其中一个。

注意:间隙可以为 0 或 负值。

例子1:假设 ( 为了简单起见 ),我们只有 3 个盒子,他们顺序如下; 块 B1 的下外边距为 M1 ( B1 没有孩子节点也没有内边距和边框 ),浮动块 F 高度为 H,块 B2 的上外边距为 M2 ( 没有内边距,边框和孩子 )。B2 的 `clear` 属性设置为 `both`。同时假设 B2 不为空。

如果不考虑 B2 的 clear 属性,我们得到下面的状态。B1 和 B2 的外边距发生折叠。假设 B1 下边框边缘在 y=0,那么 F 的上边在 y=M1 处,B2 的上边框边缘在 y=max(M1,M2),F 的下边在 y=M1+H

我们同时假设 B2 没有在 F 下面,即,我们处在标准中说明的需要添加间隙的情况。这意味着:

1
max(M1,M2) < M1+H

我们需要计算两次间隙 C,C1 和 C2,然后保留大的那一个 C=max(C1,C2)。第一种方式要把 B2 的上边和 F 的下边对其,即在 y=M1+H。这意味着,由于外边距不再和他们之间的间隙折叠,则有:

1
2
3
F 的 bottom = B2 的上边框边缘 <=>
M1 + H = M1 + C1 + M2 <=>
C1 = M1 + H - M1 - M2 = H - M2

第二种计算保持 B2 的顶部所在的位置,即 y=max(M1,M2):

1
2
max(M1, M2) = M1 + C2 + M2 <=> 
C2 = max(M1, M2) - M1 - M2

我们假设 max(M1, M2) < M1 + H,即有:

1
2
C2 = max(M1, M2) - M1 - M2 < M1 + H - M1 - M2 = H - M2 =>
C2 < H - M2

又有 C1 = H - M2,所以有:

1
C2 < C1

因此:

1
C = max(C1, C2) = C1
例子2:一个例子说明负的间隙的情况,此时间隙是 -1em。( 假设没有元素有边框和内边距 ):
1
2
3
4
5
6
7
8
<p style="margin-bottom: 4em">
First paragraph.

<p style="float: left; height: 2em; margin: 0">
Floating paragraph.

<p style="clear: left; margin-top: 3em">
Last paragraph.

解释:如果没有 clear,第一段和最后一段的外边距会折叠同时最有一段的上边框边缘会和浮动元素的上边对齐。但是 clear 要求上边框边缘在浮动元素下方。即比现在低 2em。这意味着需要考虑间隙。据此,外边距不再折叠,间隙被设置,使得 间隙 + margin-top = 2em,即 间隙 = 2em - margin-top = -1em

如果这个属性被设置在浮动元素上,他会导致对浮动元素定位的规则的修改。一个额外的约束 ( #10 ) 被加入:

  • 浮动元素的上外边距必须在其之前的左浮动元素 ( 如果 clear: left ) 或者之前的右浮动元素 clear: right 或者所有浮动元素 ( clear: both ) 的外边距之下。

**注意。**这个属性可以应用在所有的 CSS1 中的元素上。标准的实现因此必需在所有元素上支持这个属性。在 CSS2 和 CSS2.2 中,clear 属性只应用在块级元素上。因此应该只在块级盒上使用这个属性。如果有实现支持了在行内元素上的 clear 属性,不进行间隙的添加,而是强制换行同时明显的插入一个或多个空行 ( 或者像 9.5 节说的将一个新行向下移动 ) 使得清除浮动的行内的行盒在对应的浮动盒下方。

绝对定位 ( Absolute positioning )

在绝对定位模型中,一个盒子相对于其包含块偏移。它完全从常规流中移除 ( 对之后的兄弟节点没有影响 )。一个绝对定位的盒子为其常规流的子节点和绝对定位的后代建立一个新的包含块。然而,绝对定位的元素的内容不会在其他盒子周围流动。他们可能会遮挡其他盒子的内容 ( 或者自己被遮挡 ),取决于重叠盒子的栈级别 ( stack level )。

当说明一个元素是绝对定位元素 ( 或者其盒子 ) 时说明元素的 position 属性值为 absoultefixed

固定定位 ( Fixed positioning )

固定定位是绝对定位的子类别。区别只是固定定位的盒子它的包含块由视口建立。对于连续媒体 ( continuous media ),固定盒子在文档滚动时不会移动。从这方面来说,他们和固定背景图片相似。对于分页媒体,固定定位盒子会出现在每页。这个对于在每页底部放置一个签名。如果一个固定的盒子比页面区域大则会被裁剪。在初始包含块中不可见的部分不会被打印。

作者可能会用固定定位创建一个框架展示。考虑下面的框架布局:

可以通过下面的 HTML 文档和样式规则实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
<HEAD>
<TITLE>A frame document with CSS</TITLE>
<STYLE type="text/css" media="screen">
BODY { height: 8.5in } /* Required for percentage heights below */
#header {
position: fixed;
width: 100%;
height: 15%;
top: 0;
right: 0;
bottom: auto;
left: 0;
}
#sidebar {
position: fixed;
width: 10em;
height: auto;
top: 15%;
right: auto;
bottom: 100px;
left: 0;
}
#main {
position: fixed;
width: auto;
height: auto;
top: 15%;
right: 0;
bottom: 100px;
left: 10em;
}
#footer {
position: fixed;
width: 100%;
height: 100px;
top: auto;
right: 0;
bottom: 0;
left: 0;
}
</STYLE>
</HEAD>
<BODY>
<DIV id="header"> ... </DIV>
<DIV id="sidebar"> ... </DIV>
<DIV id="main"> ... </DIV>
<DIV id="footer"> ... </DIV>
</BODY>
</HTML>

displaypositionfloat 的关系

影响盒子生成和布局的三个属性 displaypositionfloat 以下面方式交互:

  1. 如果 display 的值为 none,那么 positionfloat 不会被应用。此时元素不会生成盒子。
  2. 否则,如果 positionabsolutefixed,盒子被绝对定位,float 的计算值为 nonedisplay 根据下表设置。盒子的位置由 top right bottom left 和盒子的包含块决定。
  3. 否则,如果 float 的值不为 none,盒子浮动且 display 根据下表设置。
  4. 否则,如果元素是根元素,display 根据下边设置,除了 list-item 在 CSS2.2 中没有定义的计算值是不是 blocklist-item
  5. 否则,display 根据设置值设置。
设置值 计算值
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
others 和设置值相同

常规流、浮动盒绝对定位的比较

为了说明常规流、相对定位、浮动和绝对定位的区别,我们提供了一系列例子,基于下面的 HTML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
<HEAD>
<TITLE>Comparison of positioning schemes</TITLE>
</HEAD>
<BODY>
<P>Beginning of body contents.
<SPAN id="outer"> Start of outer contents.
<SPAN id="inner"> Inner contents.</SPAN>
End of outer contents.</SPAN>
End of body contents.
</P>
</BODY>
</HTML>

我们假设这个文档有下面的规则:

1
2
3
4
body { display: block; font-size:12px; line-height: 200%; 
width: 400px; height: 400px }
p { display: block }
span { display: inline }

由盒子内外元素生成的盒子的最终位置在每个例子中会发生变化。下面的插图中,左边的数字表示常规流中双倍空间 ( 为了更清晰 ) 的行。

注意。本节的插图是说明性的,他们用来说明不同的定位方式在 CSS2.2 中的区别,并不用来给出渲染效果图。

常规流

考虑下面的对 outerinner 的 CSS 声明,它们不改变盒子的常规流:

1
2
#outer { color: red }
#inner { color: blue }

P 元素包含所有的行内内容:匿名行内文本和两个 SPAN 元素。因此,所有元素都在一个行内格式化上下文中进行布局,在一个由 P 建立的包含块中,产生的效果如下:

相对定位

为了观察相对定位的影响,我们指定:

1
2
#outer { position: relative; top: -12px; color: red }
#inner { position: relative; top: 12px; color: blue }

文本流正常的在 outer 元素中流动。outer 文本接着根据其在常规流的位置和尺寸在第一行结尾流动。接着,包含文本的行内盒 ( 分布在三行中 ) 统一移动 -12px ( 向上 )。

inner 中的内容,由于是 outer 的孩子,会在 “of outer contents” ( 在 1.5 行 ) 之后流动。然而,inner 的内容自己相对于 outer 内容偏移了 12px (向下),于是在第二行回到了自己原来的位置。

注意 outer 之后的内容不受 outer 的相对定位影响。

同时注意如果 outer 的偏移为 -24pxouter 的文本会和 body 的文本发生重叠。

浮动盒

现在考虑浮动的影响,使用下面规则使 inner 元素向右浮动:

1
2
#outer { color: red }
#inner { float: right; width: 130px; color: blue }

文本正常的出现在 inner 中,inner 本身被从流中取出并浮动到右边距 ( width 已经设置 )。浮动元素右边的行盒变短了,同时文档保持文本在其中流动。

为了展示 clear 属性,我们添加一个兄弟节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
<HEAD>
<TITLE>Comparison of positioning schemes II</TITLE>
</HEAD>
<BODY>
<P>Beginning of body contents.
<SPAN id=outer> Start of outer contents.
<SPAN id=inner> Inner contents.</SPAN>
<SPAN id=sibling> Sibling contents.</SPAN>
End of outer contents.</SPAN>
End of body contents.
</P>
</BODY>
</HTML>

下面的规则:

1
2
#inner { float: right; width: 130px; color: blue }
#sibling { color: red }

使 inner 像之前一样浮动到右边,同时文档保持在腾出的空间流动:

然而,如果 clear 被应用在了兄弟节点并设为 right ( 即,兄弟盒不会紧挨着 (next to) 在它右边的一个浮动盒 ),兄弟盒的内容从浮动元素下面开始流动:

绝对定位

最后,我们考虑绝对定位的影响。考虑下面的 CSS 声明:

1
2
3
4
5
6
7
#outer { 
position: absolute;
top: 200px; left: 200px;
width: 200px;
color: red;
}
#inner { color: blue }

这回导致 outer 的顶部会根据其包含块定位。绝对定位盒的包含块由最近的定位了的祖先元素建立 ( 或者如果不存在的话,为初始包含块,比如本例子 )。outer 的顶部在包含块的顶部下 200px,左侧在包含块的左侧 200pxouter 的子盒在其父节点中正常的流动。

下面的例子说明一个绝对定位的盒子是一个相对定位盒子的孩子节点的情况。尽管父节点 outer 并没有偏移,但是设置 positionrelative 意味着这个盒子可能被作为其子定位元素的包含块。由于 outer 是一个有很多行的行内盒,第一个行内盒的顶部和左边缘用来设置 topleft 的偏移 ( 在图上用虚线表示 )。

1
2
3
4
5
6
7
8
9
10
#outer { 
position: relative;
color: red
}
#inner {
position: absolute;
top: 200px; left: -100px;
height: 130px; width: 130px;
color: blue;
}

结果看起来像这样:

如果不对 outer 定位:

1
2
3
4
5
6
7
#outer { color: red }
#inner {
position: absolute;
top: 200px; left: -100px;
height: 130px; width: 130px;
color: blue;
}

inner 的包含块变为初始包含块。下图说明了 inner 最终的位置。

相对和绝对定位可能会用来实现 change bars,就像下面例子展示的。下面的片段:
1
2
3
4
5
<P style="position: relative; margin-right: 10px; left: 10px;">
I used two red hyphens to serve as a change bar. They
will "float" to the left of the line containing THIS
<SPAN style="position: absolute; top: auto; left: -1em; color: red;">--</SPAN>
word.</P>

会产生下面结果:

首先,段落正常的流动 ( 其包含块的两侧也在图中给出 )。接着它相对于包含块的左边缘偏移了 10px ( 因此,段落有一个 10px 的右边距 )。两个连字符作为 change bar 被从流中移出同时定位在当前行 ( 由于 top: auto ),相对于包含块 ( 由 P 最终的位置建立 ) 的左边缘偏移 -1em。结果 change bar 看起来像浮动在当前行的左边。

层表示 ( Layered presentation )

指定栈级别 ( stack level ):z-index 属性

表格参见文档

对于定位的元素,z-index 属性指定了:

  1. 一个盒子在当前栈上下文中的栈级别 ( stack level )。
  2. 是否一个盒子建立一个栈上下文。

取值有如下含义:

<integer>
该整数表示生成盒在当前栈上下文中的的栈级别。同时盒子建立一个新的栈上下文。

auto
当前栈上下文中的生成盒的栈级别为 0。如果盒子有 position: fixed,或者是根节点,它还会生成一个新的栈上下文。

本节中,“在…前面” 表示当用户面向屏幕时里用户更近。

在 CSS2.2 中,每一个盒子都在三个维度定位。除了他们的水平和垂直定位,盒子们还在一个 z 轴上布局,并且一个在另一个上面的进行格式化。z 轴定位和盒子发生视觉上的重叠时有关。本节讨论盒子们怎么在 z 轴上定位。

渲染树渲染到画布上的顺序使用栈上下文描述。栈上下文可以包含更多的栈上下文。一个栈上下文对于其父亲栈上下文是原子的;在其他上下文中的盒子不会出现在其任何两个盒子中间。

每一个盒子都属于一个栈上下文 (stack context) 。每一个在栈上下文中的定位盒子都有一个栈级别 ( stack level ),用来决定其相对于其他同栈上下文中的栈级别元素在 z 轴上的位置。一个栈级别更高的盒子通常在一个低栈级别的前面。栈级别可以为负数。相同栈级别的元素根据其在文档树中的位置从后往前布局。

根元素形成根栈上下文。其他栈上下文由 z-index 的计算值不为 auto 的定位元素形成 ( 包括相对定位元素 )。栈上下文没有必要和其包含块相关。在以后的 CSS 中,其他属性可能会产生栈上下文,例如 opacity

在每个栈上下文中,下面的层会从后往前绘制:

  1. 形成栈上下文的元素的背景和边框。
  2. 负栈级别的子栈上下文。(小值优先)
  3. 流内、非行内级、非定位子节点。
  4. 非定位的浮动元素。
  5. 流内、行内级、非定位子节点,包括行内表 ( inline tables ) 和行内块 ( inline blocks )。
  6. 栈级别为 0 的子栈上下文和栈级别为 0 的定位子节点。
  7. 栈级别为正的子栈上下文。 (小值优先)

在每个栈上下文中,栈级别为 0 的元素 ( 在第六层 ),非定位浮动元素 ( 第四层 ),行内块和行内表 ( 第五层 ) 绘制时好像这些元素生成了新的栈上下文,除非他们的定位子节点和任何将会是 ( would-be ) 子栈上下文的栈上下文参与了当前的栈上下文。

绘制顺序递归地应用在每个栈上下文上。对于栈上下文的绘制顺序形成了一个细节的规范定义的概览,参见 Appendix E

下面例子中,盒子的栈级别 (使用它们的 id 命名):`text2=0`,`image=1`,`text3=2`、`text1=3`。`text2` 的栈级别从根节点继承,其他的通过 `z-index` 属性指定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
<HEAD>
<TITLE>Z-order positioning</TITLE>
<STYLE type="text/css">
.pile {
position: absolute;
left: 2in;
top: 2in;
width: 3in;
height: 3in;
}
</STYLE>
</HEAD>
<BODY>
<P>
<IMG id="image" class="pile"
src="butterfly.png" alt="A butterfly image"
style="z-index: 1">

<DIV id="text1" class="pile"
style="z-index: 3">
This text will overlay the butterfly image.
</DIV>

<DIV id="text2">
This text will be beneath everything.
</DIV>

<DIV id="text3" class="pile"
style="z-index: 2">
This text will underlay text1, but overlay the butterfly image
</DIV>
</BODY>
</HTML>

上面例子说明了透明性的概念。背景的默认行为是让其后的盒子可见。在例子中,每一个盒子都透明地覆盖在其下面的盒子上。这个行为可以用一个存在的 background 属性重写。

文本方向 directionunicode-bidi 属性

一致的用户代理如果不支持双向文字可能会忽略 directionunicode-bidi 属性。例外的情况是用户代理渲染了从右向左的符号由于系统包含这种字体,但实际上,其并不支持从右向左文本的概念。

在一些特定的脚本 ( script ) 中,符号从右向左书写。某些文档中,特别是使用阿拉伯语和希伯来语的脚本书写的文档,同时,在某些混合语言的上下文中,在一个块 ( 具有可见的 display ) 中可能会有多种方向。这个现象叫做双向性 ( bidirectionality ) ,或者 写作 “bidi”。

Unicode 的标准定义了一个复杂的算法,用来决定文本合适的方向。该算法包含基于符号属性的隐含部分和一个具体控制嵌入 ( embeddings ) 和重写 ( overrides ) 的部分。CSS2.2 依赖于这个算法来实现合适的双向渲染。directionunicode-bidi 属性允许作者控制文档中的语言的元素和属性如何映射到这个算法。

支持双向文本的用户代理必需在每个不被强制中断 ( forced break ) 或块分割 ( block boundary ) 的行内级盒序列上应用 Unicode 双向性算法 ( Unicode bidirectional algorithm )。这个序列在算法中形成一个段落单元 ( “paragraph” unit )。段落的嵌入级 ( embedding level ) 根据包含块的 direction 属性确定而不是在 Unicode 算法中的 P2 和 P3 步骤启发式的获得。

由于文本的方向取决于文档语言的结构和语义,这些属性多数情况下被 DTDs ( document type descriptions ) 的设计者或者特殊文档的作者使用。如果默认的样式表指定了这些属性,作者和用户不应该覆盖它们。

HTML 4 标准定义了 HTML 元素的双向行为。实现双向性的样式表规则在 HTML 4 中的 the sample style sheet 中指定。HTML 4 标准同时也包含更多关于双向性的问题。

表格参见文档

该属性指定了块中的书写方向和 Unicode 算法中嵌入和覆盖的方向 ( 见 unicode-bidi )。 另外,它指定了表格的列布局,水平方向的溢出,当 text-align: justify 时块中不完整的行的位置。

取值有以下含义:

ltr
从左向右的方向

rtl
从右向左的方向

为了让 direction 属性可以影响行内元素的重排,unicode-bidi 的取值必须为 embedoverride

注意direciton 属性用来为表格列元素指定时,它不会被单元格继承因为列在文档树中不是单元格的祖先。因此,CSS不能简单地捕获 ( capture ) HTML 4 中 11.3.2.1 中描述的 dir 属性继承规则。

表格参见文档

取值有如下含义:

normal
元素不会开启一个双向性算法中的新的嵌入级别。对于行内元素,隐含的重排工作会跨过元素边界。

embed
如果一个元素是行内的,该值开启一个新的嵌入级别。该级别的方向由 direction 指定。在元素内,重排隐含地完成。这对应着添加一个 LRE ( U+202A; 对于 direction: ltr ) 或 RLE ( U+202B; 对于 direction: rtl ) 在元素的开始处。然后添加一个 PDF ( U+202C ) 在元素尾部。

bidi-override
对于行内元素,创建一个覆盖。对于块容器元素为其不在其他块容器中的行内级后继创建一个覆盖。这意味元素内,严格按照 direction 属性指定的值进行重拍;算法的隐含部分被忽略。这对应着添加一个 LRO ( U+202D; 对于 direction: ltr ) 或 RLO ( U+202E; 对于 direction: rtl ) 在元素的开始处或者在每个匿名孩子块盒的开始处,如果有的话。然后添加一个 PDF ( U+202C ) 在元素尾部。

最终每个块容器盒中的符号的顺序和添加了 bidi 控制码的之后的效果相同,标记被移除,结果的符号序列传递给了用于纯文本的 Unicode 算法,同时产生和有样式的文本相同的断行。在这个过程中,display: inline 的替换元素被看做中立符号 ( neutral characters ),除非 unicode-bidi 属性被设置为非 normal 的值,此时 它们被看做强 ( strong ) 符号在元素指定的 direction 中。其他原子行内级盒始终认为是中立符号。

请注意为了使得行内盒可以按一个统一的方向流动 ( 都从左向右或从右向左 ) ,可能会有更多的行内盒被创建 ( 包括匿名行内盒 ),同时一些行内盒可能会在流动前被分割重排。

由于 Unicode 算法限制了最多有 61 级的嵌入,所以要小心使用 unicode-bidi 取值为 normal,除非必要。特别的,取值 inherit 要特别小心使用。!!!!!!!!

下面的例子展示了一个有双向文本的 XML 文档。这说明了一个很重要的原则:DTD 设计者需要把 bidi 纳入考虑,无论是在语言 ( 元素和属性 ) 还是任何伴随的样式表中。bidi 规则需要被设计,使得 bidi 规则从其他样式规则中分离出来。bidi 规则不应该被其他样式表覆盖,这样使得文档的语言或 DTD 的 bidi行为可以被保护。

在下面的例子中,小写字母代表继承的从左向右的符号,大写代表从右向左。
1
2
3
4
5
6
7
8
9
<HEBREW>
<PAR>HEBREW1 HEBREW2 english3 HEBREW4 HEBREW5</PAR>
<PAR>HEBREW6 <EMPH>HEBREW7</EMPH> HEBREW8</PAR>
</HEBREW>
<ENGLISH>
<PAR>english9 english10 english11 HEBREW12 HEBREW13</PAR>
<PAR>english14 english15 english16</PAR>
<PAR>english17 <HE-QUO>HEBREW18 english19 HEBREW20</HE-QUO></PAR>
</ENGLISH>

由于这是 XML,样式表需要设置书写方向。下面是样式表:

1
2
3
4
5
6
7
/* Rules for bidi */
HEBREW, HE-QUO {direction: rtl; unicode-bidi: embed}
ENGLISH {direction: ltr; unicode-bidi: embed}

/* Rules for presentation */
HEBREW, ENGLISH, PAR {display: block}
EMPH {font-weight: bold}

HEBREW 元素是一个方向为从右向左的块,ENGLISH 元素是一个方向为从左向右的块。PARs 的方向继承自它们的父节点。因此,前两个 PARs 从右上方开始读,最后三个 PARs 从左上开始读。注意 HEBREW 和 ENGLISH 只是为了更明确;通常,元素名字应该表达结构而不是引用一个语言。
EMPH 元素是一个行内级元素,而且由于其 unicode-bidi 值为 normal ( 其初始值 ),他对文本的顺序没有影响。另一方面,HE-QUO 元素创建了一个嵌入。
这个文本的格式化结果如下,如果行够长的话:

5WERBEH 4WERBEH english3 2WERBEH 1WERBEH

8WERBEH 7WERBEH 6WERBEH

english9 english10 english11 13WERBEH 12WERBEH

english14 english15 english16

english17 20WERBEH english19 18WERBEH

注意 HE-QUO 的嵌入使得 HEBREW18 在 english19 的右边。
如果行被打断,看起来更像这样:

2WERBEH 1WERBEH

EH 4WERBEH english3-

5WERB

EH 7WERBEH 6WERBEH-

8WERB

english9 english10 en-

glish11 12WERBEH

13WERBEH

english14 english15

english16

english17 18WERBEH

20WERBEH english19

由于 HEBREW18 需要在 english19 前读取,所以它在 english19 上方。紧紧从之前的格式化结果把长的行切断是不行的。同时注意 english19 的第一个音节可能会适合上一行,但是对于从右向左上下文中的从左向右的单词或相反的情况下的连字符通常会被禁止以避免在一行中间出现连字符。