打印

RD1021: 各浏览器中包含 MARQUEE 元素及替换元素的包含块的 shrink-to-fit 宽度计算存在差异

作者:蔡美纯 陆远

标准参考

根据 CSS2.1 规范中的描述,如果一个浮动元素的 'width' 是 'auto',并且它是一个非替换元素,那么它的宽度将会是shrink-to-fit。

shrink-to-fit的计算公式:min(max(preferred minimum width, available width), preferred width)

CSS2.1 并未给出 preferred minimum width、available width 和 preferred width 确切算法,通常,将内容中非明确的换行外的其他部分强制不换行来计算 preferred width;反之,尝试将内容尽可能的换行,以得到 preferred minimum width;available width 即该元素的包含块的宽度减去 'margin-left','border-left-width','padding-left','padding-right','border-right-width','margin-right' 的值以及任何存在的纵向滚动条的宽度。

关于浮动非替换元素宽度计算的详细资料,请参考 CSS2.1 规范 10.3.5 Floating, non-replaced elements 中的内容。

问题描述

若容器中包含 MARQUEE 元素,且容器遵循 shrink-to-fit 宽度算法,则容器及 MARQUEE 元素的宽度在不同浏览器中存在差异。

造成的影响

此问题可能导致页面布局与不同浏览器不一致。

受影响的浏览器

所有浏览器  

问题分析

MARQUEE 不属于 W3C 规范中的元素,它最初由 IE2.0 引入,目前它已成为事实标准,所有浏览器均支持 MARQUEE 元素。

首先观察 MARQUEE 元素的一个特有现象:marquee.html

<!DOCTYPE html> <html> <head> </head> <body style="font:20px 'Trebuchet
                MS';"> <div style="width:200px; background:wheat;">
                <span>before</span> <marquee style="background:lightskyblue;
                vertical-align:bottom;">MARQUEE</marquee> <span>after</span> </div>
                <br /> <div style="width:200px; background:wheat;">
                <span>before</span> <marquee style="background:lightskyblue; width:50px;
                vertical-align:bottom;">MARQUEE</marquee> <span>after</span> </div>
                </body> </html>

上面代码中第一个 MARQUEE 元素没有设定宽度,则其 'width' 特性为初始值 'auto';第二个 MARQUEE 元素设定了宽度 50px。

各浏览器中运行效果均相同:

MARQUEE 元素在未设定宽度时 (width:auto),其表现得像块级元素,会占满其包含块,有点类似 width:100%。当为 MARQUEE 元素显式地设定一个宽度后,其表现得像行内元素。

此外,

  • MSDN 关于 MARQUEE 元素也有说明:The default width of the MARQUEE element is equal to the width of its parent element. 同时在 IE 中 MARQUEE 元素会触发 hasLayout 特性。

  • Firefox 中 MARQUEE 元素 'width' 特性的默认值为 '-moz-available',其含义与 MSDN 中的描述相同。
  • WebKit 内核中也提到 MARQUEE 元素是一种行内和块级混合型元素。参考 WebKit 源文件 RenderBox.cpp bool RenderBox::sizesToIntrinsicWidth(WidthType widthType) const

  • 分析以下代码:marquee_stf.html

    <!DOCTYPE html> <html> <head> <style> * { margin:0; padding:0; font:20px
                    'Trebuchet MS'; } </style> </head> <body> <body> <div
                    style="width:300px; background:gray; overflow:hidden;"> <div style="float:left;
                    background:wheat;"> <marquee style="background:lightskyblue;
                    vertical-align:bottom;">MARQUEE</marquee> </div> <br /><br /><br
                    /> <div style="float:left; background:wheat;"> <img
                    style="background:lightskyblue; width:100%;" src="google.gif" /> </div>
                    </div> </body> </html>

    上面两组代码中,一组为 MARQUEE 元素,另一组为 IMG 元素。MARQUEE 元素没有设定宽度,IMG 元素设定了宽度 100%。这两个元素均位于一个遵照 shrink-to-fit 算法计算宽度的包含块内。

    在各浏览器中效果如下:

    IE6 IE7 IE8(Q) IE8(S) Chrome Safari Opera Firefox

    首先解释 Firefox 中的差异:Firefox 中 MARQUEE 元素及其包含块 shrink-to-fit 计算宽度均为 IE8(S)、Chrome 中的 3 倍,这是由于 MARQUEE 元素在中使用 DIV 元素模拟。浏览器内部会在 MARQUEE 元素自身标记与其内容之间生成三层 DIV 元素,并通过 JavaScript 脚本控制 MARQUEE 元素的各种行为。而其中的一个生成的 DIV 元素设定了 margin: 0 [width],脚本通过调整 scroll 值实现 MARQUEE 的滚动效果。所以实际上 MARQUEE 元素内部真正宽度为 margin-left:[width]、[width]、margin-right:[width],这也是最终 shrink-to-fit 计算后的宽度出现了 3 倍的原因。

    而在 IE6 IE7 IE8(Q) 中,MARQUEE 元素由于其特殊的宽度特性,以及其自身触发 hasLayout 特性,这导致其将 shrink-to-fit 的包含块撑大。

    下面设定了 width:100% 的 IMG 元素同样反映出这个现象。此外,其他替换元素在设定了 width:100% 后,也有类似现象。

    解决方案

    给 MARQUEE 元素及替换元素定义具体的宽度,保证各浏览器兼容。

    参见

    知识库

    相关问题

    测试环境

    操作系统版本: Windows 7 Ultimate build 7600
    浏览器版本: IE6
    IE7
    IE8
    Firefox 3.6.11
    Chrome 9.0.570.0 dev
    Safari 5.0.2
    Opera 10.63
    测试页面: marquee.html
    marquee_stf.html
    本文更新时间: 2010-11-05

    关键字

    shrink-to-fit marquee 替换元素