打印

RD3029: IE6 IE7 IE8(Q) 中空的非替换行内元素渲染方式存在差异

作者:钱宝坤

标准参考

非替换行内元素的高度由 'line-height' 特性值决定,'margin'、'padding'、'border' 都不加入行内框高度的计算 (也不参加线框高度的计算),但是他们还是在行内框周围得到渲染。

具体描述请参考 CSS 2.1 规范的 10.8.1 Leading and half-leading

行内非替换元素的宽度不由 'width' 属性决定,他的实际宽度由其中的内容具体宽度决定,如果为空元素,那么宽度的计算值自然也就是 0。

具体描述请参考 CSS 2.1 规范的 10.2 Content width: the 'width' property

根据标准文档描述可以断定,如果空的行内非替换元素存在 'margin'、'padding'、'border' 值,不管实际宽度是否为 0,他都应被渲染出来。

问题描述

当页面中存在一个空的非替换行内元素时,如果给这个元素设置了边框或者背景样式,那么在 IE6 IE7 IE8(Q) 中这些样式将无法显示出来。

造成的影响

有可能造成局部布局效果不尽人意。

受影响的浏览器

IE6 IE7 IE8(Q)  

问题分析

这个问题发生在普通非替换行内元素上,根据 HTML 4.0 规范定义,一般常用的此类元素有:A,ABBR1,ACRONYM,B,BDO,BIG,CITE,CODE,DEL,DFN,EM,FONT,I,INS,KBD,LABEL,Q,S,SAMP,SMALL,SPAN,STRIKE,STRONG,SUB,SUP,TT,U,VAR 等。

【注】:ABBR 元素在 IE6 浏览器中存在脚本处理问题可参考文章 BT9023: IE6 中对 ABBR 元素的相关实现有误 ,本文中将不把此元素列为测试范畴。

以下代码将通过脚本程序构建三组行内非替换元素,并通过样式表让他们都拥有了 'border'、'padding'、'background' 等特性。其中,第一组是空标记形式;第二组是非空标记形式;第三组是触发了 IE hasLayout 特性的空标记形式。

他们都被绑定了 click 事件,以便在样式不显示时,可以通过点击节点来证明他们的盒模型已经被渲染,以及只是显示样式没有被渲染。另外,可以根据 CSS 2.1 规范描述得知,这三组元素的框以及背景都应该给被渲染出来。

<style>
a,acronym,b,bdo,big,cite,code,del,dfn,em,font,i,ins,kbd,label,q,s,samp,small,span,strike,strong,sub,sup,tt,u,var
{font-size:30px; line-height:50px; border:10px solid gold; padding:10px; background:yellow url(w3c.gif);  cursor:pointer;}
div.info{font-size:12px; line-height:18px; color:#060; background:#EEE;margin:30px 0 30px 0;}
</style>
<script>
var inlineElements = {
  'a':'<a></a>',
  'acronym':'<acronym></acronym>',
  'b':'<b></b>',
  'bdo':'<bdo></bdo>',
  'big':'<big></big>',
  'cite':'<cite></cite>',
  'code':'<code></code>',
  'del':'<del></del>',
  'dfn':'<dfn></dfn>',
  'em':'<em></em>',
  'font':'<font></font>',
  'i':'<i></i>',
  'ins':'<ins></ins>',
  'kbd':'<kbd></kbd>',
  'label':'<label></label>',
  'q':'<q></q>',
  's':'<s></s>',
  'samp':'<samp></samp>',
  'small':'<small></small>',
  'span':'<span></span>',
  'strike':'<strike></strike>',
  'strong':'<strong></strong>',
  'sub':'<sub></sub>',
  'sup':'<sup></sup>',
  'tt':'<tt></tt>',
  'u':'<u></u>',
  'var':'<var></var>'
}

function getElementSize(element){
  return {w:element.offsetWidth,h:element.offsetHeight};
}

function getStyle(element,styleName){
  return (element.currentStyle)
    ?  element.currentStyle[styleName.replace(/-[a-z]/g, function() {
      return arguments[0].charAt(1).toUpperCase();
    })]
    : (document.defaultView && document.defaultView.getComputedStyle)
      ? document.defaultView.getComputedStyle(element, null).getPropertyValue(styleName)
      : null ;
}

function bindEvent(element,eventName,fn){
  element["on"+eventName] = fn;
}

function buildElementInfo(tagName,element){
  var elementSize = getElementSize(element);
  document.writeln('<div class="info">');
  document.writeln(tagName,' 标记的宽为:',elementSize.w,'px; ','标记的高为:',elementSize.w,'px; ', 'display 值为:', getStyle(element,'display'));
  document.writeln("</div>");
}
function buildElement(title,type,html){
  var elementSize,element;
  document.write(title);
  for (var i in inlineElements) {
    document.writeln('<div>');
    document.write(i," Tag:");
    document.write(inlineElements[i]);
    document.writeln("其他文本内容……");
    document.writeln('</div>');
    element = document.getElementsByTagName(i)[type];
    (type==2) && (element.style.zoom = "1");
    element.innerHTML = html;
    buildElementInfo(i,element);
    bindEvent(element,"click",(function(i){return function(){alert(i+" 标记被点击")}})(i))
  }
}

buildElement("<h2>空非替换行内元素渲染情况</h2>",0,"");
buildElement("<h2>非空的非替换行内元素渲染情况</h2>",1,"hello");
buildElement("<h2>触发了 IE6 IE7 IE8(Q) 中 hasLayout 特性的空非替换行内元素渲染情况</h2>",2,"");
</script>

各浏览器运行结果如下:

  IE6 IE7 IE8(Q) IE8(S) Firefox Opera Chrome Safari
空的非替换行内元素渲染情况
边框是否被渲染
背景色是否被渲染
背景图是否被渲染
是否可被点击
非空的非替换行内元素渲染情况
边框是否被渲染
背景色是否被渲染
背景图是否被渲染
是否可被点击
触发了 hasLayout 特性的空的非替换行内元素渲染情况
边框是否被渲染
背景色是否被渲染
背景图是否被渲染
是否可被点击

根据实际运行结果汇总表可以看出:

  • IE6 IE7 IE8(Q) 中:
    • 空的非替换行内元素的边框和背景没有被渲染,虽然此时已经不能通过脚本取得他们的具体宽高,但是由 'padding'、'border' 特性够成的盒模型渲染占位依然存在,元素可以具有视觉占位空间并且可以被点击到。
    • 非空的非替换行内元素以及触发了 IE 专有 hasLayout 特性的 非替换行内元素以则无此问题,均渲染正常。
    • 从 IE 浏览器的发展历史来推断,最初版本的 IE6 渲染引擎编写时还处于 CSS 1.0 规范执行时期,然而在 CSS 1.0 规范的 4.4 The height of lines 节内并没有明确说明 'margin'、'padding'、'border' 等特性是否还在行内框周围得到渲染。 因此,这很可能是造成 IE6 出现此问题的根源,之后的 IE7 版本依然疏忽了此问题的存在,直至 IE8(S) 以后才被修复。
  • IE8(S) Firefox Chrome Safar Opera 中,不管元素是否为空都可以正常渲染边框和背景。

解决方案

应尽量避免使用的空的非替换行内元素,以及避免为空元素添加显示用样式。

参见

知识库

相关问题

测试环境

操作系统版本: Windows 7 Ultimate build 7600
浏览器版本: IE6
IE7
IE8
Firefox 3.6.10
Chrome 7.0.544.0 dev
Safari 5.0.2
Opera 10.62
测试页面: ie_empty_inline_element_render.html
本文更新时间: 2010-10-25

关键字

IE inline non-replace inline element border background hasLayout 空非替换行内元素 渲染