打印

RD3020: 在不同的文档模式中,当唯一的非表单控件类行内替换元素存在于其包容块中时,其父框的行高并不一定会计算文本基线高度

作者:钱宝坤

标准参考

关于 'vertical-align' 属性说明请参照 W3C CSS 2.1 规范:http://www.w3.org/TR/CSS21/visudet.html#propdef-vertical-align

关于基线 ( baseline ) 标准判定参见 : http://people.w3.org/rishida/docs/unicode-tutorial/part6#baseline

关于替换元素的说明,请参考 W3C CSS 2.1 规范描述:http://www.w3.org/TR/CSS21/conform.html#replaced-element

关于行高设定,请参考 W3C CSS 2.1 规范描述: http://www.w3.org/TR/CSS21/visudet.html#propdef-line-height

关于行内替换元素高度计算的说明,请参考 W3C CSS 2.1 规范描述:http://www.w3.org/TR/CSS21/visudet.html#inline-replaced-height

问题描述

在非标准文档模式中(包括混杂模式和近乎标准模式),当唯一的非表单控件类行内替换元素存在于其包容块中时,其父框的行高并不一定会计算文本基线高度。

造成的影响

在标准模式下,IMG、IFRAME、OBJECT 三个行内替换元素与其父框底部会产生一定间隙。

受影响的浏览器

IE8(S) Firefox Chrome Safari  

问题分析

文档模式说明:

这个问题与浏览器文档模式有关,从现有资料分析,浏览器一般拥有三种文档模式:标准模式( Standards Mode )、近乎标准模式( Almost Standards Mode )和混杂模式( Quirks Mode )。

他们可以由文档头部的 DTD 声明触发。常见情况中:

  1. 触发标准模式
    • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    • <!DOCTYPE html >
  2. 触发混杂模式
    • 没有写 DTD 声明
    • <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    • <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    • <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
  3. 触发近乎标准模式
    • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

关于更详细的文档模式说明请参考: http://hsivonen.iki.fi/doctype/

其中说明了 IE6 IE7 中没有标准模式,即使设置了可触发标准模式的 DTD 也仅运行在近乎标准模式中。

 

行高样式 'line-height' :

在行高部分,规范说明中提及——行高所指定的高度用于行框的高度计算,但需除去行内替换元素,其高度设定来自于 ‘height’ 属性设置 。

此样式的默认值是 "normal",它的说明如下:

Tells user agents to set the used value to a "reasonable" value based on the font of the element.

即:当其为默认值时,将基于字体尺寸计算出一个 "合理" 的值。

 

垂直对齐样式 'vertical-align' :

此样式不可继承,负责影响垂直位置上行内框在行框中产生的位置,它的默认值为 'baseline'。

此时对齐方式为:

Align the baseline of the box with the baseline of the parent box. If the box does not have a baseline, align the bottom margin edge with the parent's baseline.

即:将行内框的基线对齐父框的基线。如果该行内框没有基线,将框的底线对齐父框的基线。

 

实际问题:

在不同的文档模式中,当唯一的行内替换元素存在于其包容块中时,其父框在使用 "normal" 行高设定值时计算出的 "合理" 行高内并不一定会包含文字基线高度。

分析以下代码:

<div style="background:#CCC; font-size:16px; font-family:simsun;">
  <img src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png"/>
</div>

在父容器 DIV 中放置了行内替换元素 IMG,且父容器内没有其他文本内容,此代码实际执行效果如下:

IE8(Q)(A)
Chrome(Q)(A)
Safari(Q)(A)
Firefox(Q)(A)
Opera(Q)(A)
运行效果截图
IE8(S)
Chrome(S)
Safari(S)
Firefox(S)
Opera(S)
运行效果截图
IE6
IE7
运行效果截图

根据规范说明,父框 DIV 元素本身并没有显式性的设置行高属性,此时 'line-height' 为默认值 ‘normal’ ,他将基于字体计算出 "合理" 行高。

行内替换元素 IMG 本身不存在基线位置,在 'vertical-align:baseline' 默认设置下,他的底边界应与父框 DIV 元素的基线位置对齐。

由于此处规范说明中存在估算词汇——"合理" 行高,这将导致各个浏览器中对容器内行高计算理解有误。

从上表中可以看出:

  • IE8 和其他浏览在近乎标准模式下父框 'line-height:normal' 样式时,计算出来的行高不预留文字基线高度,导致行内替换元素的底边直接与父框底边对齐。
  • IE8 和其他浏览在标准模式下父框 'line-height:normal' 样式时,计算出来的行高是预留了文字基线高度,行内替换元素的底边直接与父框基线位置对齐,因此产生了底部有一些间隙的现象。

IE6 IE7 浏览器在此时显得有些特殊,从表象上看他们均与其他浏览器标准模式显示效果相同。但是有个细节需要注意,代码中父容器标记 DIV 与子标记 IMG 之间存在换行符,这是否会导致 IE6 IE7 浏览器中产生文本节点并促使父框在计算 ”合理“行高时预留基线高度呢?

IE6 IE7 浏览器修改代码,避免因换行造成出现文本节点,看看是否会因此导致父框 (也就是 line box) 产生基线:

<div style="background:#CCC; font-size:16px; font-family:simsun;"><img src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png"/></div>
IE6
IE7
IE8(Q)(A)
Chrome(Q)(A)
Safari(Q)(A)
Firefox(Q)(A)
Opera(Q)(A)
运行效果截图
IE8(S)
Chrome(S)
Safari(S)
Firefox(S)
Opera(S)
运行效果截图

实际运行结果证明了刚才的猜测,以上 IE6 IE7 表现是由于产生了文本节点使父框存在基线。当标签间紧密相连没有换行符等任何其他字符存在时,父框内不会产生基线。

根据这个情况可以判断出如果父框内没有产生文本元素,在混杂模式和近乎标准模式中同样不会计算文本基线高度。

将 DIV 中加入文本内容,分析以下代码:

<div style="background:#AAA;">
  <img src="http://www.google.com/intl/en_ALL/images/srpr/logo1w.png"/><span style="background:gold;">Bg</span>
</div>

实际执行效果如下:

IE6
IE7
IE8
Chrome
Safari
Firefox
Opera
运行效果截图

此时所有浏览器在所有三种文档模式下均显示一致,说明在有其他文本内容的情况下,行高计算时将文本基线高度计算在内,行内替换元素在 'baseline' 对齐方式下遵守规范描述。

综上所述,所有浏览器在混杂模式和近乎标准模式中,如果父元素本身没有任何文本内容,使用 "line-height:normal" 设置时所计算出来的 "合理" 行高内不会考虑文本基线高度。

而标准模式中任何情况下则会计算文本行基线高度,因而底部会产生由文本基线高度带来的间隙空间。

【注】:其他常用非表单控件类型的行内替换元素也会受这种情况影响,比如 IFRAME 和 OBJECT 标记;为了简化本文,他们将不再说明,如有需要请在测试页面内观看效果。

解决方案

如果在 非标准模式 中,需要父容器在仅有行内替换元素的情况下计算出包含文本基线高度的行高值,则必须加入其他行内文本元素。相反的,如果在 标准模式 中,需要行内替换元素与其父容器底部无间隙,请修改 'vertical-align' 值为非 'baseline' 。

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6
Chrome 4.0.211.4
Safari 4.0.4
Opera 10.51
测试页面: parent_baseline_in_quirks_doctype.html
parent_baseline_in_almost_standards_doctype.html
parent_baseline_in_standards_doctype.html
本文更新时间: 2010-07-22

关键字

IMG baseline vertical-align 文本高度 DTD doctype 文档模式