打印

RM8012: IE6 IE7 IE8(Q) Firefox Opera 中绝对定位元素的静态位置计算某些情况下会出错

作者:陆远

标准参考

当一个元素的 'position' 特性不是 'static' 时,这个元素被称为 "定位的" ,此时定位元素生成的定位框由 'top' 、 'right' 、 'bottom' 、 'left' 特性决定。当 'top' 、 'right' 、 'bottom' 、 'left' 特性没有设置,为默认的 'auto' 时,绝对定位的元素可能会被放置在其 "静态位置" 上。 "静态位置" 粗略地说是指元素如果在正常流中的位置。具体来说: "静态位置" 的包含块是若一个元素的 'position' 为 'static' 、 'float' 为 'none' 时生成元素的第一个框的假想框。

相关资料:

CSS Level 2 Revision 1, 9.3 Positioning schemes;

CSS Level 2 Revision 1, 9.7 Relationships between 'display', 'position', and 'float';

CSS Level 2 Revision 1, 10.3.7 Absolutely positioned, non-replaced elements (Width);

CSS Level 2 Revision 1, 10.6.4 Absolutely positioned, non-replaced elements (Height)。

问题描述

若绝对定位元素没有设置其 'top' 、 'right' 、 'bottom' 、 'left' 特性,则这四个特性的值为默认的 'auto' ,由于各浏览器对规范理解的差异,会导致页面布局差异。

造成的影响

严重的情况下会破坏整体布局。

受影响的浏览器

IE6 IE7 IE8(Q) Firefox Opera  

问题分析

1.inline元素对 "静态位置" 的影响:

对于没有设置 'top'、'right'、'bottom'、'left' 偏移量的绝对定位元素,当其前一个兄弟元素是行内元素时。

分析以下代码:

<style> * { margin:0; padding:0; font:12px Tahoma; line-height:110%; } h3 { font-size:12px;
                font-weight:bold; margin-bottom:5px; } .container { background:#DDD; width:95px; height:70px;
                margin-bottom:3px; } .in { display:inline; } .bl { display:block; width:45px; } .ib {
                display:inline-block; width:45px; } .prev { background:#BBB; } .pos { position:absolute; width:45px;
                height:45px; } .next { background:#777; } html* .ib { display:inline; } </style> <div
                style='float:left; display:inline; margin-right:3px;'> <h3>POSITIONED</h3> <div
                class='container'> <span class='prev in'>INLINE</span><span class='pos next
                in'>INLINE POS</span> </div> <div class='container'> <span class='prev
                in'>INLINE</span><div class='pos next bl'>BLOCK POS</div> </div> <div
                class='container'> <span class='prev in'>INLINE</span><div class='pos next
                ib'>INLINE BLOCK POS</div> </div> </div> <div style='float:left;
                display:inline;'> <h3>STATIC</h3> <div class='container'> <span class='prev
                in'>INLINE</span><span class='next in'>INLINE STATIC</span> </div> <div
                class='container'> <span class='prev in'>INLINE</span><div class='next bl'>BLOCK
                STATIC</div> </div> <div class='container'> <span class='prev
                in'>INLINE</span><div class='next ib'>INLINE BLOCK STATIC</div> </div>
                </div>

上面一组代码中,均是第一个左浮动 DIV 里均是一个行内元素之后包含一个没有设置偏移位置的绝对定位元素,分别测试绝对定位元素是行内、块、行内块时的情形。第二组则是去除了绝对定位特性,为默认的 'position:static' ,即 "静态位置" 。

在各浏览器中效果如下:

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

可见,各浏览器对于右侧 'position:static' 是显示效果一致,而对于绝对定位元素:

  • 在 IE6 IE7 IE8(Q) 中,浏览器并没有根据绝对定位元素的 "静态位置" 为其定位,而是由于绝对定位元素之前是一个行内元素,就将绝对定位元素直接放置在该行内元素同一行之后的位置上;
  • 在 Firefox Opera 中,对于绝对定位元素是行内及块元素时,其位置与其 "静态位置" 相符,但是当绝对定位元素是 'display:inline-block' 时,它被放置在了行内元素的下一行上;
  • 在 IE8(S) Chrome Safari 中,绝对定位元素的位置与其 "静态位置" 相符,符合 W3C 对绝对定位元素的规定。

2.block元素对 "静态位置" 的影响:

对于没有设置 'top'、'right'、'bottom'、'left' 偏移量的绝对定位元素,当其前一个兄弟元素是块元素时,所有浏览器均会将绝对定位元素显示在该块元素下方新的一行上。

分析以下代码:

<style> * { margin:0; padding:0; font:12px Tahoma; line-height:110%; } h3 { font-size:12px;
                font-weight:bold; margin-bottom:5px; } .container { background:#DDD; width:95px; height:70px;
                margin-bottom:3px; } .in { display:inline; } .bl { display:block; width:45px; } .ib {
                display:inline-block; width:45px; } .prev { background:#BBB; } .pos { position:absolute; width:45px;
                height:45px; } .next { background:#777; } html* .ib { display:inline; } </style> <div
                style='float:left; display:inline; margin-right:3px;'> <h3>POSITIONED</h3> <div
                class='container'> <span class='prev bl'>BLOCK</span><span class='pos next
                in'>INLINE POS</span> </div> <div class='container'> <span class='prev
                bl'>BLOCK</span><div class='pos next bl'>BLOCK POS</div> </div> <div
                class='container'> <span class='prev bl'>BLOCK</span><div class='pos next
                ib'>INLINE BLOCK POS</div> </div> </div> <div style='float:left;
                display:inline;'> <h3>STATIC</h3> <div class='container'> <span class='prev
                bl'>BLOCK</span><span class='next in'>INLINE STATIC</span> </div> <div
                class='container'> <span class='prev bl'>BLOCK</span><div class='next bl'>BLOCK
                STATIC</div> </div> <div class='container'> <span class='prev
                bl'>BLOCK</span><div class='next ib'>INLINE BLOCK STATIC</div> </div>
                </div>

上面一组代码中仅仅是将上一节中每个【container】中的第一个 inline 元素换为了 block 元素,其他保持不变。

在各浏览器中效果如下:

All Browsers

可见,此时所有浏览器对于绝对定位元素的位置判断均相同,且符合 "静态位置" 。这是由于绝对定位元素之前的兄弟元素已经为块级元素,产生了换行。无论上节中浏览器如何判断位置,绝对定位的元素都将显示在新的一行上。

3.inline-block元素对 "静态位置" 的影响:

对于没有设置 'top'、'right'、'bottom'、'left' 偏移量的 绝对定位元素,当其前一个兄弟元素是行内块元素时,在 IE6 IE7 IE8(Q) 中会将其的位置放置在行内元素同一行;在 IE8(S) Chrome Safari 中会参照其 "静态位置" 放置;在 Firefox Opera 中当绝对定位元素的 'display' 特性为 'inline-block' 时,将换行显示。

分析以下代码:

<style> * { margin:0; padding:0; font:12px Tahoma; line-height:110%; } h3 { font-size:12px;
                font-weight:bold; margin-bottom:5px; } .container { background:#DDD; width:95px; height:70px;
                margin-bottom:3px; } .in { display:inline; } .bl { display:block; width:45px; } .ib {
                display:inline-block; width:45px; } .prev { background:#BBB; } .pos { position:absolute; width:45px;
                height:45px; } .next { background:#777; } html* .ib { display:inline; } </style> <div
                style='float:left; display:inline; margin-right:3px;'> <h3>POSITIONED</h3> <div
                class='container'> <span class='prev ib'>INLINE-BLOCK</span><span class='pos next
                in'>INLINE POS</span> </div> <div class='container'> <span class='prev
                ib'>INLINE-BLOCK</span><div class='pos next bl'>BLOCK POS</div> </div>
                <div class='container'> <span class='prev ib'>INLINE-BLOCK</span><div class='pos
                next ib'>INLINE BLOCK POS</div> </div> </div> <div style='float:left;
                display:inline;'> <h3>STATIC</h3> <div class='container'> <span class='prev
                ib'>INLINE-BLOCK</span><span class='next in'>INLINE STATIC</span> </div>
                <div class='container'> <span class='prev ib'>INLINE-BLOCK</span><div class='next
                bl'>BLOCK STATIC</div> </div> <div class='container'> <span class='prev
                ib'>INLINE-BLOCK</span><div class='next ib'>INLINE BLOCK STATIC</div> </div>
                </div>

上面一组代码中仅仅是将上一节中每个【container】中的第一个 'inline' 元素换为了 'inline-block' 元素,其他保持不变。

在各浏览器中效果如下:

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

可见,对于绝对定位元素之前的兄弟元素为 'display:inline-block' 时的情况与 'display:inline' 时类似。

4.float元素对 "静态位置" 的影响:

分析以下代码:

<style> * { margin:0; padding:0; font:12px Tahoma; line-height:110%; } h3 { font-size:12px;
                font-weight:bold; margin-bottom:5px; } .container { background:#DDD; width:95px; height:70px;
                margin-bottom:3px; } .in { display:inline; } .bl { display:block; } .ib { display:inline-block;
                width:45px; } .prev { float:left; } .pos { position:absolute; width:45px; height:45px; } .opa {
                opacity:0.5; filter:alpha(opacity=50); } .next { background:#777; } html* .ib { display:inline; }
                </style> <div style='float:left; display:inline; margin-right:3px;'>
                <h3>POSITIONED</h3> <div class='container'> <span
                class='prev'>FLOAT</span><span class='pos next in opa'>INLINE POS</span>
                </div> <div class='container'> <span class='prev'>FLOAT</span><div class='pos
                next bl opa'>BLOCK POS</div> </div> <div class='container'> <span
                class='prev'>FLOAT</span><div class='pos next ib opa'>INLINE BLOCK POS</div>
                </div> </div>

上面代码中,浮动元素后的兄弟元素为没有设置偏移位置的绝对定位元素,分别测试绝对定位元素是行内、块、行内块时的情形。

在各浏览器中效果如下:

IE6 IE7 IE8(Q) IE8(S) Chrome Safari Firefox Opera 静态位置

可见,当绝对定位元素之前的兄弟元素为浮动元素时:

  • 在 IE8(S) Chrome Safari 中,绝对定位元素的 "静态位置" 与其在 'position:static' 时最为符合;
  • 在 IE6 IE7 IE8(Q) 中,无论绝对定位元素的 'display' 特性为何值,均不会覆盖浮动元素;
  • 在 Firefox 中,仅当绝对定位元素的 'display' 特性为 'inline' 时,不会覆盖浮动元素;
  • 在 Opera 中,无论绝对定位元素的 'display' 特性为何值,均会覆盖浮动元素。

解决方案

首先对于绝对定位元素,应尽可能避免使其 'top'、'right'、'bottom'、'left' 特性的值均为 'auto'。若必须这么做,则尽可能的保证绝对定位元素之前的兄弟元素为非浮动的块级元素。

参见

知识库

  • ...

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6
Chrome 4.0.302.3 dev
Safari 4.0.4
Opera 10.60
测试页面: RM8012-1.html
RM8012-2.html
RM8012-3.html
RM8012-4.html
本文更新时间: 2010-07-19

关键字

position absolute left top right bottom auto 绝对 定位