9 视觉格式化模型

内容

9.1 视觉格式化模型简介

本章及下一章描述了视觉格式化模型:对于可视化媒体,用户代理怎样处理文档树

在视觉格式化模型中,文档树中的每个元素根据其盒模型生成0个或多个盒。这些盒的布局由(以下因素)控制:

本章及下一章中定义的属性适用于连续媒体分页媒体margin属性应用于分页媒体时有不同的含义(详细信息请查看页模型

视觉格式化模型并没有指定格式化的所有方面(例如,它没有指定字母间距算法)。(与CSS规范)一致的用户代理在这些本规范未提及的格式化问题上的表现可能存在差异

9.1.1 视口(viewport)

连续媒体的用户代理一般会给用户提供一个视口(屏幕上的一个窗口或者视图区域),用户通过它来查阅文档。视口尺寸变化(见初始包含块)时,用户代理可能会改变文档的布局

当视口比渲染文档的画布区域小时,用户代理应该提供一种滚动机制。一个画布最多对应一个视口,但用户代理可能会渲染到多个画布上(即提供同一文档的不同视图)

9.1.2 包含块(Containing block)

CSS 2.1中,很多盒的位置和大小是根据被称为包含块的矩形框的边界计算的。一般把生成的盒作为后代盒的包含块,我们说一个盒为其后代“建立”了包含块。“一个盒的包含块”表示“盒所在的包含块”,而不是它生成的(包含块)

每个盒都根据其包含块确定了一个位置,但它不受该包含块的限制,可能会溢出

关于如何计算包含块尺寸的细节下一章

9.2 控制盒生成

下面的各节描述了CSS 2.1中可能生成的盒的类型。盒的类型对其在视觉格式化模型中的行为有一定影响。下面描述的'display'属性指定了盒的类型

9.2.1 块级元素与块盒

块级元素是源文档中那些被格式化成视觉上的块的元素(例如,段落)。'display'属性的下列值能让一个元素变成块级的:'block','list-item'和'table'

块级盒是参与块格式化上下文的盒。每个块级元素生成一个主块级盒(principal block-level box),用来包含后代盒及生成的内容,并且任何定位方案都与该盒有关。有些块级元素可能会生成除主盒外的额外的盒:'list-item'元素。这些额外的盒根据主盒来放置

除了后面章节描述的表格盒与替换元素外,一个块级盒也是块容器盒。一个块容器盒要么只包含块级盒,要么建立了行内格式化上下文并因此只包含行内盒。不是所有的块容器盒都是块级盒:非替换的行内块与非替换的表格单元是块级容器,但不是块级盒。作为块级容器的块级盒也叫块盒

“块级盒(block-level box)”,“块容器盒(block container box)”和“块盒(block box)”这三个术语在没有歧义的时候就简称为“块(block)”

9.2.1.1 匿名块盒

在一个这样的文档中:


<DIV>
  Some text
  <P>More text
</DIV>

(假设DIV和P都有'display: block'),DIV似乎既有行内内容也有块内容。为了更容易定义格式化,我们假设在"Some text"四周有一个匿名块盒

diagram showing the three
boxes for the example above   [D]

上例图片展示了3个盒,其中一个匿名的

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

当行内盒包含流内块级盒时,该行内盒(及与它处于同一行框里的行内祖先)会打破周围的块级盒(以及任何连续的或只被可合并的空白符和/或流外元素隔开的块级兄弟),把行内盒分成两个盒(即使有一边是空的),分别位于块级盒的两边。拆分前的行框与拆分后的行框都被包进匿名块盒,并且该块级盒作为这些匿名盒的兄弟。当这样一个行内盒受到相对定位的影响时,任何由此产生的位移也会影响行内盒里面的块级盒

示例:

此模型会应用于下例,如果下列规则:


p    { display: inline }
span { display: block }

被应用在如下HTML文档的话:


<!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的匿名块盒

匿名盒的属性是从周围的(enclosing)非匿名盒继承来的(例如,“匿名块盒”小节的标题下面那个示例中,DIV的盒),不可继承的属性取其初始值。例如,匿名盒的字体是从那个DIV继承的,但margin将是0

设置在让匿名块盒生成的元素上的属性仍然会应用于该元素(生成的)盒与内容。例如,如果一个border被设置在上例中的P元素上,border将会绘制在C1(在行结束的位置打开)和C2(在行开始的位置打开)周围

有些用户代理以它们的方式给行内包含块实现了border。例如,通过把这种嵌套块包进“匿名行框”并且因此在这些盒周围绘制行内边框。因为CSS1和CSS2没有定义这种行为,只支持CSS1的和只支持CSS2的用户代理可能会实现这种替代模型,并仍声称与CSS 2.1的这部分一致。这不适用于在本规范发布后开发的UA

在处理相关的百分比值时,匿名块盒会被忽略:用最近的非匿名祖先盒代替。例如,如果上面DIV里面的匿名块盒的孩子需要知道其包含块的高度,以处理百分比高度,那么它将采用DIV形成的包含块的高度,而不是匿名块盒的

9.2.2 行内级元素与行内盒

行内级元素是源文档中那些不会形成新内容块的元素,内容分布于多行(例如,强调段落中的一部分文本,行内图片等等)。'display'属性的下列值能让一个元素变成行内级:'inline','inline-table'和'inline-block'。行内级元素生成行内级盒,即参与行内格式化上下文的盒

行内盒是(特殊的)行内级盒,其内容参与了它的包含行内格式化上下文(containing inline formatting context)。'display'值为'inline'的非替换元素会生成一个行内盒。不属于行内盒的行内块级盒(例如,行内级替换元素,inline-block元素和inline-table元素)被称为原子行内级盒(atomic inline-level boxes),因为它们作为单一的不透明盒(opaque box)参与其行内格式化上下文

9.2.2.1 匿名行内盒

任何被直接包含在一个块容器元素中(不在行内元素里面)的文本,必须视为一个匿名行内元素

在一个有如下HTML标记的文档里:


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

<p>会生成一个块盒,里面还有几个行内盒。"emphasized"的盒是一个由行内元素(<em>)生成的行内盒,但其它盒("Some"和"text")都是由块级元素(<p>)生成的行内盒。后者叫做匿名行内盒,因为它们没有与之相关的行内级元素

这种匿名行内盒从它们的父级块盒继承了可继承的属性,不可继承的属性取其初始值。示例中,匿名行内盒的颜色是从P继承的,但背景是透明的

对于后续会根据'white-space'属性合并起来的空白字符内容,不会生成任何匿名行内盒

如果知道上下文中匿名盒是哪种含义,本规范中的匿名行内盒和匿名块盒都可以简称为匿名盒

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

9.2.3 Run-in盒

[本节之所以存在是为了保持节序号与之前的草案一致,'Display: run-in'现在定义在CSS level 3中(见CSS基本盒模型)]

9.2.4 'display'属性

'display'
Value:  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
Initial:  inline
Applies to:  所有元素
Inherited:  no
Percentages:  N/A
Media:  all
Computed value:  见下文

属性值的含义如下:

block
该值会让元素生成一个块盒
inline-block
该值会让元素生成一个行内级块容器(inline-level block container)。一个inline-block的内部会被格式化成一个块盒,而该元素本身会被格式化成一个原子行内级盒
inline
该值会让元素生成一个或多个行内盒
list-item
该值会让元素(例如,HTML中的LI)生成一个主块盒(principal block box)和一个标记盒(marker box)。关于列表及列表格式化示例的更多信息请查看列表章节
none
该值会让元素不在格式化结构(formatting structure)中出现(即在视觉媒体中,元素不会生成盒也不会影响布局)。后代元素也不会生成任何盒,该元素及其内容会从格式化结构中全部移除。这种行为不能通过给后代设置'display'属性来重写

注意,display为none时不会创建一个不可见的盒,它根本不会创建任何盒。CSS提供了一种让一个元素在格式化结构中生成能影响格式化的但本身不可见的盒的机制。详细信息请查看可见性章节

tableinline-tabletable-row-grouptable-columntable-column-grouptable-header-grouptable-footer-grouptable-rowtable-celltable-caption
这些值会让元素表现得像个表格元素一样(相关限制在表格章节中讨论)

(display属性的)计算值与指定值相同,除了定位元素(positioned)和浮动元素(见'display','position'与'float'之间的关系)以及根元素。对于根元素,计算值的变化描述在'display','position'与'float'之间的关系章节

注意,尽管'display'初始值是'inline',用户代理默认样式表中的规则可能会重写该值。见附录中HTML 4的样例样式表

示例:

有一些'display'属性的示例:


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

9.3 定位方案

CSS 2.1中,一个盒可能会根据三种定位方案来布局:

  1. 常规流 CSS 2.1中,常规流包括块级盒的块格式化(block formatting),行内级盒的行内格式化和块级与行内级盒的相对定位
  2. 浮动 在浮动模型中,盒先根据常规流来放置,然后从常规流中取出来并尽可能远地向左或向右移动。其它内容可能沿着浮动(盒)的一侧排列(Content may flow along the side of a float)
  3. 绝对定位 在绝对定位模型中,一个盒会从常规流中全部移除(它不会影响后面的兄弟元素)并根据包含块确定位置

如果一个元素是浮动的,绝对定位的或者是根元素,它就叫流外(out of flow)(元素)。如果一个元素不是流外的,就叫流内(in-flow)(元素)。(流外)元素A是由A和所有最近的流外祖先为A的流内元素组成的集合(The flow of an element A is the set consisting of A and all in-flow elements whose nearest out-of-flow ancestor is A.译注:这句话假定A是个流外元素,一般只对流外元素讨论“元素的流”,因为流内元素的流只包括该元素自己,流外元素的流包括自身及所有后代元素,除了被包进其它流外元素的)

注意 CSS 2.1的定位方案帮助编写者让他们的文档可读性更好,让他们避免那些用来实现布局效果的标记技巧(mark-up tricks)(例如,不可见的图片)

9.3.1 选择定位方案: 'position'属性

'position''float'属性决定了用哪种CSS 2.1定位算法来计算盒的位置

'position'
Value:  static | relative | absolute | fixed | inherit
Initial:  static
Applies to:  所有元素
Inherited:  no
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

属性值的含义如下:

static
盒是个常规盒,根据常规流布局。'top''right''bottom''left'属性失效
relative
盒的位置是根据常规流计算的(被称为常规流中的位置),然后盒相对于其常规位置偏移。当盒B为相对定位时,后面的盒的位置仍按照B没有偏移量来计算。table-row-group,table-header-group,table-footer-group,table-row,table-column-group,table-column,table-cell和table-caption元素上'position:relative'的效果是未定义的
absolute
盒的位置(及可能的大小)由'top''right''bottom''left'属性指定,这些属性指定了相对于盒的包含块的偏移量。绝对定位的盒脱离了常规流,意味着它们不会影响后面兄弟元素的布局,而且,虽然绝对定位的盒有外边距,但它们不会与任何其它外边距合并
fixed
除了盒相对于某些参照(reference)是固定的(fixed)之外,盒的位置根据'absolute'模型来计算。如同'absolute'模型一样,盒的外边距不会与任何其它外边距合并。媒体类型为handheld,projection,screen,tty和tv的情况下,该盒相对于视口固定,并且滚动时不会移动。媒体类型为print时,该盒在每一页都会呈现,并且相对于页盒(page box)固定,即使页面是通过一个视口看到的(例如,打印预览时)。对于其它媒体类型,表现是未定义的。编写者可能希望以一种依赖媒体(media-dependent)的方式指定'fixed'。例如,一个编写者可能想让一个盒保持在屏幕视口顶部,但不出现在每一个打印页的顶部。可以用@media规则把它们分开,例如:

示例:

   
@media screen { 
  h1#first { position: fixed } 
}
@media print { 
  h1#first { position: static }
}

UA不能对fixed盒的内容分页。注意,UA可能会以其它方式打印不可见的内容,见第13章“页盒外的内容”

用户代理可以把根元素的position视为'static'

9.3.2 盒偏移:'top''right''bottom''left'

如果元素的'position'属性有一个除'static'外的值,就说它是定位元素(positioned)。定位的元素生成定位的盒(positioned boxes),根据以下4个属性布局:

'top'
Value:  <length> | <percentage> | auto | inherit
Initial:  auto
Applies to:  定位的元素
Inherited:  no
Percentages:  参照包含块的高度
Media:  visual
Computed value:  如果指定了一个长度,就是对应的绝对长度;如果指定了一个百分比,就是指定的值;否则就是'auto'

该属性指定了一个绝对定位的盒的上外边距边界离盒的包含块的上边界有多远。对于相对定位的盒,偏移量参照该盒自身的上边界(例如,该盒在常规流中给定了一个位置,然后根据这些属性从原位置偏移)

'right'
Value:  <length> | <percentage> | auto | inherit
Initial:  auto
Applies to:  定位的元素
Inherited:  no
Percentages:  参照包含块的宽度
Media:  visual
Computed value:  如果指定了一个长度,就是对应的绝对长度;如果指定了一个百分比,就是指定的值;否则就是'auto'

与'top'类似,只是指定了一个盒的右外边距边界离该盒包含块的右边界有多远。对于相对定位的盒,偏移量参照该盒自身的右边界

'bottom'
Value:  <length> | <percentage> | auto | inherit
Initial:  auto
Applies to:  定位的元素
Inherited:  no
Percentages:  参照包含块的高度
Media:  visual
Computed value:  如果指定了一个长度,就是对应的绝对长度;如果指定了一个百分比,就是指定的值;否则就是'auto'

与'top'类型,只是指定了一个盒的下外边距边界离该盒包含块的下边界有多远。对于相对定位的盒,偏移量参照该盒自身的下边界

'left'
Value:  <length> | <percentage> | auto | inherit
Initial:  auto
Applies to:  定位的元素
Inherited:  no
Percentages:  参照包含块的宽度
Media:  visual
Computed value:  如果指定了一个长度,就是对应的绝对长度;如果指定了一个百分比,就是指定的值;否则就是'auto'

与'top'类似,只是指定了一个盒的左外边距边界离该盒包含块的左边界有多远。对于相对定位的盒,偏移量参照该盒自身的左边界

这4个属性的值含义如下:

<length>
偏移量是到参照边的固定距离。允许负值
<percentage>
偏移量是包含块宽度(对于'left''right')或高度(对于'top''bottom')的百分比。允许负值
auto
对于非替换元素,该值的效果取决于那些相关的值也是'auto'的属性。非替换元素的详细情况,见绝对定位widthheight章节。对于替换元素,该值的影响只取决于替换内容的固有尺寸。替换元素的详细情况,见绝对定位的widthheight章节

9.4 常规流(Normal flow)

常规流中的盒属于一个格式化上下文,可能是块或是行内(格式化上下文),但不能两者都是。块级盒参与块格式化上下文。行内级盒参与行内格式化上下文

9.4.1 块格式化上下文

浮动,绝对定位的元素,非块盒的块容器(例如inline-blocks,table-cells和table-captions),以及’overflow’不为’visible’的块盒(当该值已被传播到视口时除外(except when that value has been propagated to the viewport))会为其内容建立新的块格式化上下文

在一个块格式化上下文中,盒在垂直方向一个接一个地放置,从包含块的顶部开始。两个兄弟盒之间的垂直距离由'margin'属性决定。同一个块格式化上下文中的相邻块级盒之间的垂直外边距会合并

在一个块格式化上下文中,每个盒的左外边界(left outer edge)挨着包含块的左外边界(对于从右向左的格式化,右外边界挨着)。即使存在浮动(尽管一个盒的行框可能会因为浮动而收缩 译注:环绕浮动元素放置的行框比正常的行短一些),这也成立。除非该盒建立了一个新的块格式化上下文(这种情况下,该盒自身可能会因为浮动变窄

关于分页媒体中分页相关的信息,请查看合法的分页章节

9.4.2 行内格式化上下文

在行内格式化上下文中,盒是从包含块的顶部开始一个挨一个水平放置的。这些盒之间的水平外边距,边框和内边距都有效。盒可能会以不同的方式垂直对齐:以它们的底部或者顶部对齐,或者以它们里面的文本的基线对齐。包含来自同一行的盒的矩形区域叫做行框

行框的宽度由包含块和浮动情况决定,行框的高度由行高的计算小节给出的规则决定

行框总是足够高,能够容纳它包含的所有盒。然而,它可能比它所包含的最高的盒还要高(例如,如果盒是以基线对齐的)。当盒B的高度小于它所在的行框的高度时,行框中B的垂直对齐方式由'vertical-align'属性决定。当几个行内级盒在水平方向上不能共存于一个行框时,它们会被分到两个或多个垂直堆叠的(vertically-stacked) 行框里。因此,段落就是个行框的垂直栈(vertical stack)。行框没有垂直间隔地堆放(除非在其它地方有特别说明)并且它们不会重叠

一般来说,一个行框的左边界挨着其包含块的左边界,右边界挨着其包含块的右边界。然而,浮动盒可能会跑到包含块边界与行框边界之间。因此,尽管同一个行内格式化上下文中的行框一般都有相同的宽度(即包含块的宽度),如果可用的水平空间因为浮动而减少了的话,它们的宽度就可能不同。同一个行内格式化上下文中的行框一般高度各不相同(例如,一行可能含有一个高图片,而其它的只含文本)

当一行的行内级盒的总宽度小于它们所在的行框的宽度时,它们在行框里的水平分布由'text-align'属性决定。如果该属性值为'justify',用户代理可能还会拉伸行内盒(不包括inline-table和inline-block盒)里的空格和单词

当行内盒超出行框宽度时,它会被分成几个盒,并且这些盒会跨多行框分布。如果一个行内块无法分割(例如,如果该行内盒(只)含单一字符,或者特定语言的单词分隔规则不允许在该行内盒里分隔,或该行内盒受到了一个值为nowrap或者pre的white-space的影响),那么该行内盒会从行框溢出

当一个行内盒被分割后,外边距,边框和内边距在发生分割的地方(或者在任何分割处,如果有多处的话)没有视觉效果

同一个行框里的行内盒也可能因为双向(bidirectional)文本处理而被分割成几个盒

需要盛放(hold)行内格式化上下文中的行内级内容时,创建一个行框。该行框不含文本、保留空白符(preserved white space)、外边距,内边距和边框非0的行内元素、 以及其它流内内容(例如,图片,行内块或行内表格),并且不以保留换行符结束的(行框)在确定其内部元素的位置时必须被当做0高度行框,出于其他目的时,必须当它不存在

有个行内盒构造的示例,下面的段落(HTML块级元素P创建的)含有匿名文本,散布在EM和STRONG元素间:


<P>Several <EM>emphasized words</EM> appear
<STRONG>in this</STRONG> sentence, dear.</P>

P元素生成了一个含有5个行内盒的块盒,其中有3个是匿名的:

为了格式化该段落,用户代理把5个盒排列(flows)在一个行框里。本例中,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")。外边距,边框,内边距或文本修饰(text decorations)不会在split1后面和split2前面产生可见的效果

考虑下例:


<!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的宽度,各盒可能分布如下:

Image illustrating the effect of line breaking on the
display of margins, borders, and padding.   [D]

9.4.3 相对定位

当一个盒根据常规流或者浮动摆放好后,它可能会相对于该位置移动,称之为相对定位。用这种方式偏移盒(B1)的位置不影响盒(B2),遵循:给定B2位置时就当B1没有偏移,并且B2在B1应用偏移之后没有重新定位(re-positioned)。这表明相对定位可能会导致盒重叠。然而,如果相对定位导致具有'overflow:auto'或'overflow:scroll'的盒溢出了的话,UA必须让用户能够访问这部分内容(在其偏移位置),此时,滚动条的创建可能会影响布局

相对定位的盒保持它在常规流中的大小,包括换行和空格都会原样保留。包含块小节解释了一个相对布局盒会在什么时候建立一个新的包含块

对于相对定位的元素,'left'和'right'水平移动盒,不会改变其大小。'left'把盒向右移,而'right'把盒向左移动。因为盒没有被分割或者拉伸,所以'left'或'right'的应用值总是(满足):left = -right

如果'left'和'right'都是'auto'(各自的初始值),应用值为'0'(即盒待在原位置)

如果'left'是'auto',其应用值为负的'right'值(即盒向左移动'right'值)

如果'right'被指定为'auto',其应用值为负的'left'值

如果'left'和'right'都不是'auto',位置就被过度约束(over-constrained)了,它们('left'和'right')其中有一个会被忽略。如果包含块的'direction'属性是'ltr',那么'left'有效,'right'变成-'left'(负的'left')。如果包含块的'direction'属性是'rtl',那么'right'有效,'left'被忽略

示例:

示例 下列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',它会变成另一个的相反数。如果都不是'auto',就忽略'bottom'(即'bottom'的应用值将是负的'top'值)

注意 脚本环境中,相对定位盒的动态移动能产生动画效果(另见'visibility'属性)。尽管相对定位可以用作上标和下标的形式,但行高不会因为其定位而自动调整。更多信息请查看行高的计算中的说明

比较常规流,浮动与绝对定位小节提供了相对定位的示例

9.5 浮动

浮动(盒)就是一个在当前行向左或向右移动的盒。浮动盒最有意思的特性是其它内容会沿着它的一侧排列(可以通过'clear'属性禁止这种行为)。其它内容会沿着左浮动盒的右侧,右浮动盒的左侧排列。下面是浮动定位及其内容流(flow)的介绍,控制浮动行为的准确规则'float'属性中的说明

一个浮动盒会向左或向右移动,直到其外边界挨到包含块边界或者另一个浮动盒的外边界。如果存在行框,浮动盒的上外(边界)会与当前行框的上(边界)对齐

如果没有足够的水平空间来浮动,它会向下移动,直到空间合适或者再没出现其它浮动

因为浮动(盒)不在(常规)流内,在浮动盒之前或者之后创建的非定位(non-positioned)块盒会垂直排列,就像浮动不存在一样。然而,会根据需要缩短挨着(next to)浮动(盒)创建的当前(行)及后续行框,以便给浮动(盒)的外边距框让出空间

行框挨着(next to)浮动盒的条件是存在一个垂直位置,同时满足这4个条件:(a)位于行框的顶端或顶端下方,(b)位于行框底端或底端上方,(c)在浮动(盒)上外边距边界下方并且(d)在浮动(盒)下外边距边界上方

注意:也就是说0外高度(outer height)或者负外高度(盒)的浮动不会缩短行框

如果一个缩短的行框小到无法容纳任何内容了,那么该行框会向下移动(并重新计算其宽度)直到有些内容能适应(它的空间)或者再没出现其它浮动了。当前行里浮动盒之前的所有内容都会在浮动方向另一侧的相同行重新排列(reflow)。换句话说,如果行内级盒被放在同一行中的左浮动元素之前,并且适应剩余的行框空间,左浮动(盒)就放在该行,与行框的顶端对齐,然后,相应地,该行中已经放好的这个内联级盒会被移动到浮动盒右边(右边是左浮动的另一侧),对于rtl和右浮动,反之亦然

表格,块级替换元素或常规流中建立了新的块格式化上下文的元素(例如一个'overflow'不为'visible'的元素)不能和与元素自身处于同一块格式化上下文中的任何浮动(盒)的外边距框重叠。如果必要的话,实现应该把它放在所有之前出现的浮动(盒)下方,以清除(clear)该元素(受到的浮动影响),如果空间充足的话,可以放得与浮动(盒)相邻。它们甚至会让该元素的边框框比10.3.3小节中定义的更窄。CSS2没有定义UA什么情况下可以把该元素挨着浮动(盒)放以及该元素可以变得多窄

示例:

示例 下面这段文档中,包含块窄到无法容纳与浮动(盒)挨着的内容了,所以内容被移动到了浮动(盒)下方,在行框中按照text-align属性对齐的位置


p { width: 10em; border: solid aqua; }
span { float: left; width: 5em; height: 5em; border: solid blue; }


...


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

效果可能像这样:

Image illustrating the effect of an unbreakable piece of content 
 being reflowed to just after a float which left insufficient room next to it 
 for the content to fit.

几个浮动(盒)可能相邻,并且该模型也适用于同一行里的相邻浮动(盒)

示例:

下列规则让所有class="icon"的IMG盒向左浮动(并设置了左外边距为0):


img.icon { 
  float: left;
  margin-left: 0;
}

考虑下面的HTML源码和样式表:

  
<!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元素建立的包含块的宽度)。该文档可能会被格式化成:

Image illustrating how floating boxes interact with
margins.   [D]

如果文档是下面这样,格式化将完全相同(exactly the same):


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

因为浮动(盒)左边的内容被浮动(盒)取代了,所以(内容)会沿着浮动盒右侧重新排列(reflow)

8.3.1小节所述, 浮动盒的外边距不会与相邻盒的外边距合并。因此,之前的示例中,P盒与浮动的IMG盒之间的垂直外边距不会合并

浮动(盒)的内容会堆叠起来,就像浮动(盒)生成了新的堆叠上下文(stacking contexts)一样,除了所有定位的元素和实际创建了新的堆叠上下文并参与了浮动(盒)的父级堆叠上下文的元素。浮动(盒)可以与常规流中的其它盒重叠(例如,当常规流盒挨着具有负外边距的浮动(盒)时),出现这种情况时,浮动(盒)会被渲染在非定位(non-positioned)流内块之前,流内行内(盒)之后

示例:

另一幅图展示了当一个浮动(盒)与常规流中元素的边框重叠时的情况

Image showing a floating image
that overlaps the borders of two paragraphs: the borders are
interrupted by the image.   [D]

浮动的图片盖住了它重叠的块盒的border

下例描述了用'clear'属性来阻止内容挨着浮动(盒)排列

示例:

假设一条这样的规则:


p { clear: left }

格式化后可能像这样:

Image showing a floating
image and the effect of 'clear: left' on the two paragraphs.   [D]

(两个)段落都被设置了'clear: left',让第二个段落被“推下去”到了浮动(盒)下方的位置—为了完成这种效果(见'clear'属性),在它的上外边距上面插入了“空隙(clearance)”

9.5.1 浮动定位: 'float'属性

'float'
Value:  left | right | none | inherit
Initial:  none
Applies to:  所有(元素),除了9.7描述的
Inherited:  no
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

该属性指定了一个盒应该向左浮动,向右浮动还是不浮动。可以给任何元素设置,但只会应用于生成了非绝对定位盒(的元素)。属性值的含义如下:

left
元素会生成一个向左浮动的盒。其它内容排列在盒的右侧,从顶部开始(受限于'clear'属性)
right
与'left'类似,但盒向右浮动,而其它内容排列在盒的左侧,从顶部开始
none
盒不浮动

用户代理可以把根元素上的float当作'none'

有几条准确的规则,用来控制浮动的行为:

  1. 左浮动盒的左外边界不能位于其包含块的左边界的左边。向右浮动的元素也有类似的规则
  2. 如果当前盒是向左浮动的,并且在这之前源文档中还有元素生成了左浮动盒,那么对于每一个之前的盒,要么当前盒的左外边界在之前的盒的右外边界的右边,要么其顶部要低于之前盒的底部。右浮动盒也有类似的规则
  3. 左浮动盒的right外边不能位于挨着它的任意右浮动盒的左外边界的右边。右浮动盒也有类似的规则
  4. 浮动盒的外顶端(outer top)不能高于其包含块的顶部。当浮动(盒)出现在两个折叠外边距(collapsing margins)之间时,浮动(盒)的定位就像它有个空的匿名块父级存在于(当前)流一样。这个父级的位置通过外边距合并章节中的规则来定义
  5. 浮动盒的外顶端不能高于源文档中任何在该元素之前的元素生成的块盒或者浮动盒的外顶端
  6. 元素的浮动盒的外顶端不能高于任何含有源文档中在该元素之前的元素生成的盒的行框的顶端
  7. 左边存在另一个左浮动盒的左浮动盒的right外边不能位于其包含块的右边界的右边(不严谨的:左浮动盒不能超出右边界,除非它已经尽量向左(紧挨着包含块的左边界)了)。右浮动元素也有类似的规则
  8. 浮动盒必须尽量往高处放
  9. 左浮动盒必须尽量往左放,右浮动盒尽量往右放。更高的位置要比更左/右的位置优先

但在CSS 2.1中,如果块格式化上下文里有一个流内负垂直外边距,导致浮动(盒)的位置在原位置(假设该负外边距被设置为0)的上方,浮动(盒)的位置是未定义的

这些规则里涉及的其它元素仅仅是指与浮动(盒)处于同一个块格式化上下文的其它元素

示例:

这段HTML会让b向右浮动

<P>a<SPAN style="float: right">b</SPAN></P>

如果P元素的宽度足够,a和b将各在一边,就像这样:

An a at the left side of a box and a b at the right side

9.5.2 控制浮动后的流:'clear'属性

'clear'
Value:  none | left | right | both | inherit
Initial:  none
Applies to:  块级元素
Inherited:  no
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

该属性说明了元素盒的哪一边不能与之前的浮动盒相邻。'clear'属性不考虑元素自身的或者其它块格式化上下文中的浮动

应用于非浮动块级盒时,属性值含义如下:

left
要求该盒的上边框边界位于源文档中在此之前的元素形成的所有左浮动盒的下外边界下方
right
要求该盒的上边框边界位于源文档中在此之前的元素形成的所有右浮动盒的下外边界下方
both
要求该盒的上边框边界位于源文档中在该元素之前的元素形成的所有左浮动盒和右浮动盒的下外边界下方
none
对该盒相对于浮动(盒)的位置没有约束

值不为'none'就隐含了要引入空隙(clearance)。空隙会阻止外边距合并,并作为元素margin-top上方的空间。用来在垂直方向上把元素推离浮动(元素)(It is used to push the element vertically past the float)

计算设置了'clear'的元素的空隙,先要确定该元素的上边框边界的假定位置。该位置是当元素的'clear'属性为'none'时其上边框边界实际所在的位置

如果该元素的上边框边界的假定位置没有越过(past)相关的浮动(盒),那么就得引入空隙,并根据8.3.1中的规则合并外边距

然后,空隙的高度(amount)被设置为下面两者的较大值:

  1. 把块的边框边界放在最低的将被clear的浮动(盒)的下外边界,所必需的高度
  2. 把块的上边框边界放在其假定位置(clear为'none'时的位置),所必需的高度

或者,空隙被精确地设置为把块的border边放在最低的将被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处

Float F extends into the margin above M2.

我们再假设B2不在F下方(垂直方向),即规范描述的那种需要添加空隙的情况,意味着:

max(M1,M2) < M1 + H

我们需要计算两次空隙C,C1和C2,取较大值:C = max(C1,C2)。第一种方法是让B2的顶端紧接着F的底端,即在y = M1 + H处。意味着,因为存在空隙,它们之间margin不再合并:

bottom of F = top border edge of B2

M1 + H = M1 + C1 + M2

C1 = M1 + H - M1 - M2

= H - M2

第二次计算保持B2位置不变,即在y = max(M1,M2)处,意味着:

max(M1,M2) = M1 + C2 + M2

C2 = max(M1,M2) - M1 - M2

我们假设max(M1,M2) < M1 + H,这意味着:

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

C2 < H - M2

并且,因为C1 = H - M2,因此:

C2 < C1

所以

C = max(C1,C2) = C1

示例:

例2 负空隙的示例,这种情况下,空隙为-1em(假设元素都没有border和padding)

<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'的话,第一个和最后一个段落的margin将会合并,并且最后一个段落的上边框边界将紧接着浮动段落的顶端。但'clear'要求上边框边界处于浮动(元素)下方。即,再低2em,这意味着必须引入空隙。因此,margin不再合并,空隙的高度被设置为clearance + margin-top = 2em,即clearance = 2em - margin-top = 2em - 3em = -1em

当该属性被设置在浮动元素上时,会改变浮动定位的规则。需要加上额外的约束(#10):

注意 该属性适用于CSS1中的所有元素,实现可能因此已经支持该属性用在所有元素上了。CSS2和CSS 2.1中,'clear'属性只适用于块级元素。因此,编写者应该只把该属性用在块级元素上。如果一个实现支持行内元素上的clear,而不像上面解释的那样设置一个空隙,该实现应该强制打断(break)并有效地插入一个或多个空行框(或者把新的行框按9.5节中描述的那样向下移动),来把带clear的行内元素的行框的顶端移到对应的浮动盒下方

9.6 绝对定位

绝对定位模型中,盒相对其包含块明确偏移,它会从常规流中全部移除(不会影响后面的兄弟)。绝对定位的盒会为常规流中的子级和绝对(不包括fixed)定位的后代建立一个新的包含块。然而绝对定位的元素的内容不会沿着任何其它盒排列。它们可能会遮住其它盒的内容(或者它们自身被遮住),取决于重叠盒的堆叠层级(stack levels)

本规范中出现的绝对定位元素(或者它的盒)表示元素的'position'属性值为'absolute'或者'fixed'

9.6.1 Fixed定位

fixed定位是绝对定位的子类(subcategory)。fixed定位的盒唯一的区别是,包含块由视口建立。对于连续媒体,当文档滚动时,fixed盒不会移动。在这一点上,它们和fixed背景图像类似。对于分页媒体,fixed定位的盒会在每一页上重复(出现)。这在排版(placing)方面很有用,例如,每一页的底部都有一个签名。fixed定位的盒比页区(page area)大的部分会被裁剪。fixed定位盒在初始包含块中不可见的部分将不会被打印

编写者可以用fixed定位来创建帧式(frame-like)展现,考虑下面的帧布局:

Image illustrating a frame-like layout with position='fixed'.   [D]

这可以通过下列HTML文档和样式规则来实现:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
  <HEAD>
    <TITLE>A frame document with CSS 2.1</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>

9.7 'display','position'与'float'之间的关系

这3个属性影响盒的生成及布局—'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'根据下表来设置,但指定值'list-item'应该变成计算值'block'还是'list-item',在CSS 2.1中是未定义的
  5. 否则,其它'display'属性值(计算值)就用指定值
Specified value Computed value
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
其它与指定值相同

9.8 比较常规流,浮动与绝对定位

为了阐述常规流,相对定位,浮动与绝对定位之间的区别,我们在如下HTML的基础上提供了一系列示例:


<!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>

该文档中,我们假设有下列规则:


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

outerinner生成的盒的最终位置在每个示例中都不一样。每幅插图中,插图左边的数字表明了常规流中双倍行距的(清晰起见)行的位置

注意,本节的图都是说明性的(illustrative)并且没按比例(绘制)。用来强调CSS 2.1中各种定位方案之间的差异,而不是为了给出示例供参考的呈现效果

9.8.1 常规流

考虑下面对outerinner的CSS声明,不会改变盒的常规流


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

P元素包含所有行内内容:匿名行内文本以及两个SPAN元素。因此,所有内容都将被放在一个行内格式化上下文中P元素建立的包含块里面,产生的结果就像这样:

Image illustrating the normal flow of text between parent and sibling boxes.   [D]

9.8.2 相对定位

为了看到相对定位的效果,我们指定:


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

文本常规排列,直到outer元素。outer文本保持其常规流位置和尺寸,位于在第1行末尾。然后,含有文本(分布在3行里)的行内盒被整体(as a unit)移动了'-12px'(向上)

inner的内容,作为outer的子元素,常规地将紧跟着单词"of outer contents"排列(在1.5行)。然而,inner内容自身相对于outer内容偏移了'12px'(向下),回到它们在第2行的原位置

注意,outer后面跟着的内容没有受到outer相对定位的影响

Image illustrating the effects of relative positioning on a
box's content.   [D]

注意,如果outer的偏移量是'-24px',outer的文本和body文本将会重叠

9.8.3 浮动盒

现在考虑浮动的效果,通过下列规则让inner元素的文本向右:


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

文本常规排列,直到inner盒,从常规流脱离,并浮动到右边缘(它的'width'已经显式赋值了),浮动(盒)左边的行框被缩短了,文档的剩余文本排列在它们里面

Image illustrating the effects of floating a box.   [D]

为了展示'clear'属性的效果,我们给示例添了一个sibling元素:


<!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>

下列规则:


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

会让inner盒像之前一样浮动到右边,文档的剩余文本排列在腾出来的空间里:

Image illustrating the effects of floating a box without
setting the clear property to control the flow of text around the
box.   [D]

然而,如果sibling元素上的'clear'属性被设置为'right'(即,生成的sibling盒将不会接受一个右侧挨着浮动盒的位置),sibling(元素的)内容从浮动(盒)下面开始排列:


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

Image illustrating the effects of floating an element with setting the clear property to control the flow of text around the element.   [D]

9.8.4 绝对定位

最后,我们考虑绝对定位的效果。考虑下面对outerinner的CSS声明:


#outer { 
    position: absolute; 
    top: 200px; left: 200px; 
    width: 200px; 
    color: red;
}
#inner { color: blue }

会让outer盒的顶端相对于其包含块定位。定位元素(positioned)盒的包含块由最近的定位的祖先(或者,如果不存在,就用初始包含块,正如我们的示例)。outer盒的顶端在包含块顶端的下方'200px'处,并且左边离(包含块的)左边为'200px'。outer的子级盒相对于其父级常规排列:

Image illustrating the effects of absolutely positioning a box.   [D]

下例展示了一个作为相对定位盒的子级的绝对定位的盒。尽管父级outer盒并没有实际偏移,设置其'position'属性为'relative',表示其(生成)盒可以为定位的后代提供包含块。因为outer盒是一个行内盒,所以被跨行分割了,第一个行内盒的上边界和左边界(下图中用粗虚线描绘的)作为'top''left'偏移的参照


#outer { 
  position: relative; 
  color: red 
}
#inner { 
  position: absolute; 
  top: 200px; left: -100px; 
  height: 130px; width: 130px; 
  color: blue;
}

产生像下面这样的结果:

Image illustrating the effects of absolutely positioning a
box with respect to a containing block.   [D]

如果我们不定位outer盒:


#outer { color: red }
#inner {
  position: absolute; 
  top: 200px; left: -100px; 
  height: 130px; width: 130px; 
  color: blue;
}

inner的包含块就成了初始包含块(在我们的示例中)。下面的插图展示了这种情况下inner盒的最终位置

Image illustrating the effects of absolutely positioning a box with respect to a containing block established by a normally positioned parent.   [D]

相对和绝对定位可能被用来实现变更指示符(change bar),如下例所示。下面的片段:


<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>

产生像这样的结果:

Image illustrating the use of floats to create a changebar effect.   [D]

首先,段落(包含块边界展示在图中的那个)常规排列。然后从包含块(因此,'10px'的right margin已经被保留为预期偏移了)的左边界偏移了'10px'。两个作为变更指示符的连字符被从流中拿了出来,并定位在当前行(由于'top: auto'),距其包含块(由P在其最终位置建立)的左边界'-1em'。产生的结果是变更指示符看起来就像“浮动”到了当前行的左端

9.9 分层展示

9.9.1 指定堆叠层级:'z-index'属性

'z-index'
Value:  auto | <integer> | inherit
Initial:  auto
Applies to:  定位(positioned)元素
Inherited:  no
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

对于定位的盒,'z-index'属性指定了:

  1. 当前堆叠上下文(stacking context)中,该盒的堆叠层级(stack level)
  2. 该盒是否(应该)建立一个堆叠上下文

(属性)值含义如下:

<integer>
该整数是生成盒在当前堆叠上下文中的堆叠层级,该盒还会建立一个新的堆叠上下文
auto
生成盒在当前堆叠上下文中的堆叠层级为0。该盒不会建立新的堆叠上下文,除非它是根元素

本节中,“在...前面”表示当用户面对屏幕时,离用户更近

CSS 2.1中,每个盒都具有一个用3个维度表示的位置。除了它们的水平和垂直位置,盒还会沿着“Z轴”排列,被格式化成一个叠在另一个上面。当盒在视觉上重叠时,Z轴位置尤为重要。本节讨论了盒可能会怎样沿着Z轴定位

渲染树绘制到画布上的顺序是根据堆叠上下文来定的,堆叠上下文可以包含堆叠上下文。从其父级堆叠上下文的角度来看,堆叠上下文是原子的(atomic),其它堆叠上下文中的盒不可能出现在它的任意盒里

每个盒都属于一个堆叠上下文。给定堆叠上下文中每个定位(positioned)盒都有一个整型堆叠层级,表示它在同一堆叠上下文中相对于其它堆叠层级的Z轴上的位置。堆叠层级更大的总被格式化在堆叠层级低的前面,盒可以有负的堆叠层级。同一个堆叠上下文中堆叠层级相同的盒按照文档树顺序从后向前堆叠

根元素形成根堆叠上下文。其它堆叠上下文由任意'z-index'的计算值不为'auto'的定位(positioned)元素(包括相对定位元素)生成,堆叠上下文不一定与包含块有关。在将来的CSS版本中,其它属性可能会引入堆叠上下文,例如,'opacity' [CSS3COLOR].

在每个堆叠上下文中,下列层按从后向前的顺序绘制:

  1. 元素的background和border生成的堆叠上下文
  2. 堆叠层级为负数的子级堆叠上下文(最负的优先)
  3. 流内的,非行内级,非定位(non-positioned )后代
  4. 非定位浮动(元素)
  5. 流内的,行内级,非定位后代,包括inline table和inline block
  6. 堆叠层级为0的子级堆叠上下文,以及堆叠层级为0的定位的后代
  7. 堆叠层级为正数的子级堆叠上下文(最小的优先)

每个堆叠上下文中,都会绘制堆叠层级为0的定位的元素(在第6层),非定位浮动(元素)(在第4层),inline block(在第5层)和inline table(在第5层),就像这些元素自身生成了新的堆叠上下文一样,除了它们的定位的后代和将要(would-be)加入当前堆叠上下文的子级堆叠上下文

该绘制顺序被递归应用于每个堆叠上下文,这里对堆叠上下文绘制顺序的描述是对附录 E中详细规范定义的概述

下例中,各个盒的堆叠层级(以它们的"id"属性命名)分别为:"text2"=0,"image"=1,"text3"=2,"text1"=3。"text2"的堆叠层级是从根元素继承的,其它的都是通过'z-index'属性指定的


<!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的默认行为是允许它后面的盒可见。本例中,每个盒都透明地覆盖在它下面的盒上。这种行为可以通过使用现有的background属性之一来覆盖

9.10 文本方向:'direction''unicode-bidi'属性

(与CSS规范)一致的不支持双向文本的用户代理可以忽略本节描述的'direction''unicode-bidi'属性。这种例外包括那些简单呈现从右向左字符的UA,因为系统字体可能含有这种情况(从右向左排列的字符),但不支持从右向左文本方向的概念

某些文字(scripts)中的字符是从右向左书写的。有些文档里,尤其是那些用阿拉伯(Arabic)或者希伯来(Hebrew)文字写的,并且在一些混合语言的(mixed-language)上下文中,单一(直观显示的)块中的文本可能以混合的方向出现。这种现象叫做双向性(bidirectionality),或者简称"bidi"

Unicode标准([UNICODE][UAX9])定义了一个复杂的算法来确定适当的文本方向。该算法包括基于字符属性的隐式部分和对嵌入与重写的显式控制。CSS 2.1依赖该算法来实现适当的双向渲染。'direction''unicode-bidi'属性允许编写者指定元素和文档语言属性如何映射到该算法

支持双向文本的用户代理必须对每个行内级盒中没有被强制(bidi class B)结束符或者块界(block boundary)隔断的(文本)序列应用Unicode双向算法,这种序列会在双向算法中形成“段落”单元。段落嵌入级别是根据包含块的'direction'属性的值来设置的,而不是由Unicode算法中步骤P2和P3中给出的启发式(信息)决定

因为文本的方向性取决于文档语言的结构和语义,这些属性大多数情况下应该只由文档类型说明(DTDs)的设计者或者特殊文档的编写者使用。如果一个默认样式表指定了这些属性,编写者和用户不应该指定规则去覆盖它们

HTML 4规范([HTML4] 8.2节)定义了HTML元素的双向性行为。[HTML4]中能能实现bidi行为的样式表规则在样例样式表中给出了。HTML 4规范还含有关于双向性问题的更多信息

'direction'
Value:  ltr | rtl | inherit
Initial:  ltr
Applies to:  所有元素,除了下文描述的(情况)
Inherited:  yes
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

该属性指定了块的基本书写方向,并为Unicode双向算法指定了嵌入和重写的方向(见'unicode-bidi')。除此之外,它还指定了一些东西,例如表格列布局的方向、水平溢出的方向、'text-align: justify'时,块中最后一个不完全的(incomplete)行的方向

该属性值的含义如下:

ltr
从左向右方向
rtl
从右向左方向

为了'direction'属性能让行内元素重新排序,'unicode-bidi'属性的值必须是'embed'或者'override'

注意 'direction'属性,给表格列元素指定时,不会被列中的单元格继承,因为在文档树中,列不是单元格的祖先。因此,CSS无法轻易获知[HTML4]的11.3.2.1节中"dir"属性的继承规则

'unicode-bidi'
Value:  normal | embed | bidi-override | inherit
Initial:  normal
Applies to:  所有元素,除了下文描述的(情况)
Inherited:  no
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

该属性值的含义如下:

normal
该元素不会根据双向算法开一个额外的嵌入层级。对于行内元素,隐式重新排序可以跨元素边界进行
embed
如果该元素是行内(元素),该值会根据双向算法开一个额外的嵌入层级,这个嵌入层级的方向由'direction'属性指定。在该元素内部,重新排序是隐式完成的。这相当于在该元素开始位置添加了一个LRE(U+202A;对于'direction: ltr')或者RLE(U+202B;对于'direction: rtl'),并在该元素结束位置添加了一个PDF(U+202C)
bidi-override
对于行内元素,会创建一个覆盖(override)。对于块容器元素,会为不在另一个块容器元素的行内级后代创建一个覆盖。意味着在该元素内部,重新排序是严格按照'direction'属性进行的,双向算法的隐式部分会被忽略。这相当于在元素开始位置或者每个匿名子级块盒的开始位置(如果有的话)添加一个LRO(U+202D;对于'direction: ltr')或者RLO(U+202E;对于'direction: rtl'),在元素的结束位置添加一个PDF(U+202C)

如果已经添加了上述的bidi控制代码,标记已经被剥离出去,产生的字符序列已经被传递给一个纯文本Unicode双向算法的实现,并产生了与样式化后的文本相同的换行的话,每个块容器中的最终字符顺序应该都一样。这个过程中,'display: inline'的替换元素被当作中性字符(neutral characters 译注:指的是没有上下文无法确定其方向性的字符,比如段落分隔符,见neutral characters),除非它们的'unicode-bidi'属性值不为'normal',此时,它们会被当作强字符(strong characters 译注:指的是那些具有明确方向性的字符,比如字母字符,见strong characters),用为该元素指定的'direction'。所有其它原子行内级盒都总被当作中性字符

注意,为了能够在一个统一方向(要么全部从左向右,要么全部从右向左)的环境中排列行内盒,可能不得不创建更多行内盒(包括匿名行内盒),一些行内盒必须在排列之前被分割开来并重新排序

因为Unicode算法有61层嵌入的的限制,应该注意不要滥用值不为'normal'的'unicode-bidi',除非必要(unless appropriate)。特别的,使用'inherit'值应该格外小心。然而,对于那些一般要显示为块的元素,如果将display更改为inline(见下例),则优先使用'unicode-bidi: embed'设置来保持元素(挨)在一起

下例演示具有双向文本的XML文档,说明了重要的设计原则:DTD设计者在考虑适当的语言(元素和属性)以及所有附带的样式表时,都应该考虑bidi。样式表应该设计得让bidi规则和其它样式规则分离开来。bidi规则不应该被其它样式表重写,以保留文档语言的或者DTD的bidi行为

示例:

本例中,小写字母代表本来(inherently)从左向右的字符,大写字母表示本来从右向左的字符:


<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,由样式表负责设置书写方向,样式表为:

/* 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元素是一个基础方向为从左向右的块。PAR都是从其父级继承基础方向的块。因此,前两个PAR是从右上角开始读的,最后的3个从左上角开始读。注意,选用HEBREW和ENGLISH作为元素名只是为了清晰起见。一般情况下,元素名应该表达语言无关的结构

EMPH元素是行内级的,因为其'unicode-bidi'值为'normal'(初始值),对文本的顺序没有影响。另一方面,HE-QUO元素创建了一个嵌入(embedding)

如果行长度很长的话,这段文本的格式可能就像这样:

               5WERBEH 4WERBEH english3 2WERBEH 1WERBEH

                                8WERBEH 7WERBEH 6WERBEH

english9 english10 english11 13WERBEH 12WERBEH

english14 english15 english16

english17 20WERBEH english19 18WERBEH

注意,HE-QUO嵌入(embedding)导致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的第一个音节(syllable)可能要放在前一行,但一般为了避免在一行的中间显示连字符,在一个从右向左的上下文中,从左向右的单词连字符通常会被禁止(hyphenation),反之亦然