在上一篇文章中,我们讲到了CSS盒模型的基本结构。在本文中,我们将继续讨论RenderBox类(继承于RenderObject类),以及关于块(block)和内联(inline)的概念。
一个块流(block flow)是一种盒类型,包括多行内容(例如,一个段落),或者其他按垂直顺序依次排列的块。在HTML里,p元素和div元素都是块流元素。
一个内联流(inline flow)则是属于一行中的某个部分。在HTML里,a元素、b元素、i元素和span元素都是内联块流元素。
在WebCore里,有3种渲染类(rendererclass)覆盖了块流和内联流。RenderBlock类,RenderInline类,以及它们的共同父类RenderFlow。
RenderFlow.h
RenderBlock.h
RenderInline.h 过CSS的display属性,可以将内联流改变为块流(反之亦然)。
div { display:inline }
span { display:block }
除了块流和内联流之外,还有一种类型元素可以扮演一个块或内联:被替换元素(replayced element)。被替换元素,是指元素的渲染不是通过CSS来指定的元素。被替换元素的内容,从该元素的左上角开始渲染。img元素、表单控件、iframe元素、插件(plugins)和JAVA小程序(applets)都属于被替换元素。
一个被替换元素可以是块级(block-level)的,也可以是内联级(inline-level)的。当被替换元素是一个块元素时,它将被依次垂直地排列,就像一个段落元素一样。当被替换元素是一个内联元素时,它就是一个段落中的一行里的一部分。默认情况下,被替换元素是一个内联元素。
表单控件属于特例。虽然它们属于被替换元素,但是,因为它们是Web引擎实现的元素,所以,实际上,它们是继承于RenderBlock类的子类。因此,“被替换元素”这一概念不能成为一个简单的、公共的子类,而是,通过RenderObject的某个成员来表示。通过isReplayced方法,可以得出对象是否一个被替换元素。
bool isReplaced() const
图像(images),插件(plugins),框架(frames),以及Java小程序(applets)都是继承于一个公共的实现了被替换元素形为的子类。这个类就是RenderReplaced类。
RenderReplaced.
内联块(The Inline Block)
在CCS里,最使人迷惑的就是“内联块(inline-block)”。首先,内联块是一个块流,另一方面,内联块又是位于一行中的。实际上,对于外部,内联块就像内联的被替换元素,而在内联块内部是块流。可以通过CSS的显示属性来创建内联块。对于内联块元素,isReplaced方法将返回true,即,内联块被当作一个被替换元素。
div { display:inline-block }
表格(Tables)
默认情况下,在HTML里,表格元素是块级元素。然而,可以通过将CSS显示属性设置为inline-table,将一个表格转换为内联元素。
table { display:inline-table }
再次强调,对于外部来说,内联表格就相当是一个内联的被替换元素(所以,isReplaced方法会返回true),但是,对于表格本身,表格仍是一个表格。
在WebCore里,RenderTable类表示一个表格。RenderTable类继承于RendeBlock类,为什么是这个继承关系将于文章后面的排版章节讲述。
RenderTable.h
文本(Text)
纯文本通过RenderText类表示。在WebCore里,文本通常被当作是内联元素,因为,它通常们于各行当中。
RenderText.h
获取块和内联信息(Getting Blockand Inline Information)
最常用的用于判断对象是块还是内联的方法是isInline方法。该方法返回对象是否是一行的一部分。它并不需要理会元素的内部(例如,文本,图片,内联流,内联块,还是内联表格)。
bool isInline()const
大家通过会误认为:在渲染树(render tree)中,isInline即表示对象是否为内联流、文本,或者内联的被替换元素。然而,对于内联块(inline-blocks)和内联表格(inline-tables),isInline方法也是返回true的。
如果需要精确判断一个对象是否是块流或内联流,就应该使用以下的方法。
bool isInlineFlow() const
bool isBlockFlow() const
这两个方法会根据对象的内部实际情况,来返回相应的结果。例如,一个内联块元素,是一个块流,而不是一个内联流。内联块元素,在外部看来,是内联的,但是,内联块内部是块流。
如果需要判断对应的类类型,可以使用以下的方法。
bool isRenderBlock() const
bool isRenderInline() const
在排版过程中,isRenderBlock方法十分有用,因为,块流和表格都是被排版对象的容器。
如果需要判断一个对象是否是内联块,或是内联表格,可以使用isInlineBlockOrInlineTable方法。
bool isInlineBlockOrInlineTable() const
块流的孩子(Children ofBlock Flows)
块流有一个关于其孩子元素的渲染树总是满足的规则。这个规则可以总结如下:
块流的孩子必须全部都是块元素或全部都是内联元素。
即,除去浮动(floating)元素和绝对定位元素,在渲染树中,块流的全部孩子的isInline方法必须都返回true,或者都返回false。为了满足这个规则,渲染树会做相应的变动。
childrenInline方法就是用于获知一个块流的孩子是否都是内联元素或块元素。
boolchildrenInline() const
内联的孩子(Children of InlineFlows)
内联流也有一个关于其孩子元素的规则。
内联流的孩子必须都是内联元素。
匿名块(Anonymous Blocks)
为了满足块流关于其孩子的规则(全部都是内联元素或全部都是块元素),渲染树将构建一些对象,这些对象名叫匿名块。考虑下面这个例子:
<div>
Sometext
<div>
Somemore text
</div>
</div>
上面的例子中,外层的div元素有两个孩子:“some text”和另外一个div元素。第一个孩子是内联元素,而第二个孩子是块元素。因为,这不满足“全是内联”或“全是块”的规则,渲染树会构建匿名块来包装文本。从而,渲染树变成以下这样:
<div>
<anonymousblock>
Sometext
</anonymousblock>
<div>
Somemore text
</div>
</div>
isAnonymousBlock方法可以告知某个渲染树节点是否一个匿名块流。
bool isAnonymousBlock() const
当一个块流既有内联元素,又有块元素时,并且,在准备将其孩子元素加入到渲染树中时,渲染树会根据需要,自动创建匿名块元素,以用来包装这些内联元素。连续的内联元素将共享一个公共的匿名块,所以,匿名块的个数将会被尽量的少。RenderBlock类的makeChildrenNonInline方法将执行上面描述的这项修正工作。
void makeChildrenNonInline(RenderObject *insertionPoint)
内联流里的块元素(Blocks insideInline Flows)
在HTML里,最另人讨厌的一种情况就是:一个块元素将放置于内联流里。下面是一个例子:
<i>Italiconly <b>italic and bold
<div>
Wow,a block!
</div>
<div>
Wow,another block!
</div>
Moreitalic and bold text</b> More italic text</i>
两个div元素,破坏了bold元素的孩子必须全部是内联元素的规则。渲染树不得不进行一系列相当复杂的操作来修正。对于上面这个例子,3个匿名块会被构建。第一个匿名块将第一个div元素之前的内联元素包含起来。第二匿名块将两个div元素包含起来。第三个匿名块将第二个div元素之后的内联元素包含起来。
<anonymouspre block>
<i>Italiconly <b>italic and bold</b></i>
</anonymouspre block>
<anonymousmiddle block>
<div>
Wow,a block!
</div>
<div>
Wow,another block!
</div>
</anonymousmiddle block>
<anonymouspost block>
<i><b>Moreitalic and bold text</b> More italic text</i>
</anonymouspost block>
注意,bold元素和italic元素的被分别分割成两个渲染树节点,因为,它们同时存在于第一个匿名块和第三个匿名块。在DOM树中,blod元素的孩子在第一个匿名块中,然后,又会到第二个匿名块中,最后,又会到第三个匿名块中。渲染树通过一个名叫“连续链(continuation chain)”的操作来连接这些对象。
RenderFlow*continuation() const
BoolisInlineContinuation() const
在第一个匿名块里的第一个bold渲染树节点,可以通过对应的DOM树中的b节点的renderer方法获得。然后,该渲染树节点的continuation方法将会返回第二个匿名块的渲染树节点。而第二个匿名块的continuation方法将返回第二个bold渲染树节点。按照这种方式,需要保证的是DOM元素的孩子所对应的渲染树节点也可以轻易地做出类似的操作。
在上面的例子中,DOM树中的i节点同样被分割。它的孩子只存在第一个和第三个匿名块中,所以,只需要一个连接操作。在第一个匿名块中的italic渲染树节点的continuation方法返回在第三个匿名块中的italic渲染树节点。
位于RenderInline.cpp文件的splitFlow方法,就是用来递归分割内联流和创建“连续链(continuationchain)”。
原文地址:http://www.webkit.org/blog/115/webcore-rendering-ii-blocks-and-inlines/