打印

RD8026: 各浏览器对于未明确设定高度的包含块内包含百分比单位高度的块级元素或行内块元素的高度计算存在差异

作者:钱宝坤

标准参考

根据 CSS2.1 规范中的描述,'height' 特性当指定百分比的值时,其百分比将参照其 包含块 的生成框高度进行计算,但当包含框未设置明确高度时,并且在设置了百分比高度的元素没有设置绝对定位的情况下将忽略该百分比高度的设定值,而改用其 'content box' 的高度。

关于 'height' 的更多信息,请参考 CSS 2.1 规范 10.5 Content height: the 'height' property 中的内容。

问题描述

各浏览器对于未明确设定高度的包含块内包含百分比单位高度的块级元素的高度计算存在差异。

造成的影响

由于各浏览器对于未明确设定高度的包含块内设置百分比单位高度的块级元素的高度计算存在差异,将造成不同浏览器中的渲染效果不同并影响依赖此高度值的其他操作结果存在差异。

受影响的浏览器

所有浏览器  

问题分析

分析以下代码:

window.onload = function () { function $(id){ return document.getElementById(id);} void function(){
                $("info1").innerHTML = "计算式:<br/>" + $("contain1").offsetHeight + "=" + $("child1").offsetHeight +
                '+' + $("child2").offsetHeight + '+' +$("child3").offsetHeight; $("info2").innerHTML = "计算式:<br/>"
                + $("contain2").offsetHeight + "=" + $("child4").offsetHeight + '+' + $("child5").offsetHeight + '+'
                +$("child6").offsetHeight; $("info3").innerHTML = "计算式:<br/>" + $("contain3").offsetHeight + "=" +
                $("child7").offsetHeight + '+' + $("child8").offsetHeight + '+' +$("child9").offsetHeight; }();
                }
<body style="margin:0; font:12px/2 'Trebuchet MS';"> <div id="display_block" style="height:100px; background:#999999;margin-bottom:5px;">
                <div id="cont1" style="width:100px;background:black; float:left;"> <div id="contain1"
                style="margin:0 10px;padding:0;"> <div id="child1" style="height:50%;
                background:#CC99FF">block1</div> <div id="child2" style="height:20%;
                background:yellow;">block2</div> <div id="child3" style="height:30%;
                background:green;">block3</div> </div> </div> <div style=" float:left;">
                <div id="info1"></div> </div> </div> <div id="display_inline-block" style="height:100px;
                background:#999999;margin-bottom:5px;"> <div id="cont2" style="width:100px;background:black;
                float:left;"> <div id="contain2" style="margin:0 10px;padding:0;"> <div id="child4"
                style="height:50%; background:#CC99FF; width:100%; display:inline-block;">inline-block1</div>
                <div id="child5" style="height:20%; background:yellow;
                width:100%;display:inline-block;">inline-block2</div> <div id="child6" style="height:30%;
                background:green; width:100%;display:inline-block;">inline-block3</div> </div>
                </div> <div style=" float:left;"> <div id="info2"></div> </div>
                </div> <div id="display_list-item" style="height:100px;
                background:#999999;margin-bottom:5px;"> <div id="cont3" style="width:100px;background:black;
                float:left;"> <div id="contain3" style="margin:0 10px;padding:0;"> <div id="child7"
                style="height:50%; background:#CC99FF; display:list-item;">list-item1</div> <div id="child8"
                style="height:20%; background:yellow; display:list-item;">list-item2</div> <div id="child9"
                style="height:30%; background:green; display:list-item;">list-item3</div> </div>
                </div> <div style=" float:left;"> <div id="info3"></div> </div>
                </div> </body>

以上代码中设置了字号和行高分别为12px和12px*21,主要分为三个 DIV 包含块,其 id 分别为: display_block、display_inline-block、display_list-item。

下面以第一个 DIV(id="display_block") 包含块为例,该包含块设置了固定高度('height:100px'), 其内主要包含的四个("contain1"2 "child1" "child2" "child3")DIV,并通过脚本将这四个 DIV("contain" "child1" "child2" "child3")元素的高度值(offsetHeight3)及他们之间的关系显示出来。

在不同浏览器中运行结果截图如下 (表一) :

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

注【1】:由于 Chrome(中文版) 中对于字号小于12px的文字自动转换为12px,这里明确固定的字号及行高是为了避免产生其他差异的干扰以便于针对此问题进行各浏览器间的对比。
注【2】:"contain1" 元素未设置 'height' 属性值,此时他的 'height' 属性值为 'auto',如果将 'height' 设置为固定值(非百分比数值)那么将不会产生浏览器差异,但若设置为百分比高度时除上述差异外,在 IE6(Q) IE7(Q) IE8(Q) 中还会产生新的差异,此差异会在稍后说明。
注【3】:'offsetHeight' 用于获取元素的高度,它获得的是 'border-edge' 的高度,本代码中由于没有设置 'border-width' 'margin-top' 'margin-bottom' 'padding' 属性的值,所以通过 'offsetHeight' 属性获得的便是该元素的 'margin box' 的高度,关于 'offsetHeight' 的相关内容请参考 CSSOM View Module 中的 8.1 The offsetParent, offsetTop, offsetLeft, offsetWidth, and offsetHeight attributes

根据 CSS2.1 规范中的描述,当 'height' 特性指定为百分比的值时,其百分比将参照其包含块的生成框高度进行计算,但由于上述代码中的 "contain1" 元素的包含块未明确设定高度 ('auto'),那么其子元素的高度计算将忽略其百分比高度的设定值,而是设定为 'auto',即为其内容 ( content box ) 的高度,本例中也就是行高*n(line-height*n)4。综上所述,依照规范中的描述 "contain1" 的高度计算式应为:72=24+24+24

从运行结果截图中的计算式可见:

  • IE6 IE7 IE8 Firefox(S) Chrome(S) Safari(S) Opera 中是按照规范中的描述进行高度计算的;
  • Chrome(Q) Safari(Q) Firefox(Q) 中将 "contain1" 包含框的高度解析为其父包含框的高度(100px),所以会出现 "contain1" 元素的高度计算式为:100=50+20+30,这与规范中的描述不符。

注【4】:"n" 为行数。

下面针对注解【2】中当 "contain1" "contain2" "contain3" 的高度为百分比时的情况,对上述代码增加 "contain1" "contain2" "contain3" 元素的高度设定如下:

<div id="contain1" style="height:100%;5
                  background:red; margin:0 10px;padding:0"> <div id="contain2" style="height:100%;background:red; margin:0 10px;padding:0"> <div
                  id="contain3" style="height:100%;background:red; margin:0
                  10px;padding:0">

注【5】:这里的 'height' 属性值设定为 '100%' 是为了与修改之前的运行结果做对比,也可以设定为其他值,只不过所有运行结果都会产生相应的变化,但对高度的计算过程仍符合本文后续内容的描述。

在各浏览器中的运行结果截图如下 (表二) :

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

下面仍以第一个 DIV(id="display_block") 包含块为例进行分析,对照表一表二,可以发现是否设置 'height:100%' 特性值,对于 Chrome(Q) Safari(Q) Firefox(Q) 中高度计算无影响,它们还是依照 "contain1" 元素包含框的高度设定自身高度值;另外对于 IE6(S) IE7(S) IE8(S) Firefox(S) Chrome(S) Safari(S) Opera 中高度计算也无影响,由于此处 "contain1" 元素的 'margin-top' 'margin-bottom' 'padding-top' 'padding-bottom' 都是0,'height:100%' 即为元素本身的 "content box" 高度,所以它们依然是遵照规范定义来计算实际高度的。

这里唯一的区别就是 IE6(Q) IE7(Q) IE8(Q) 中高度的计算结果有变化,它们的计算式为:84=36+24+24,其运算过程如下:

  1. 按照规范中的描述得到计算式:72=24+24+24
  2. 由步骤一可知,按照规范描述计算后 "contain1" 元素的高度h=72px,再利用 "h" 的值分别重新计算出 "child1" 的高度h1=72*50%=36px,"child2" 的高度h2=72*20%=14px(此处取整),"child3" 的高度h3=72*30%=22px(此处取整)
  3. 这里以 "h1" 为例,若 "h1" 小于步骤一中按照规范描述计算的到的 "child1" 的高度 "H1",则 "child1" 的最终高度为 "H1",若 "h1" 大于等于 "H1",则 "child1" 的最终高度为 "h1";
  4. 按照步骤三的方法计算出 "child2" "child3" 的最终高度分别为:22px、22px,对这三者的最终高度求和即为 "contain1" 元素的最终高度,得到计算式:84=36+24+24

对于 'display:inline-block' 和 'display:list-item' 的高度计算情况与上述分析相同,可参照代码进行测试与理解。

解决方案

要对设置有百分比高度的块级元素的包含块设置明确的 'height' 属性值。

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6.10
Chrome 7.0.517.8 dev
Safari 5.0.2
Opera 10.62
测试页面: height_auto_q.html
height_auto_s.html
height_percent_q.html
height_percent_s.html
本文更新时间: 2010-09-21

关键字

height containing block inline-block list-item percent 包含块 宽度 高度 百分比