打印

RM8001: 各浏览器对 'display' 特性值的支持程度不同

作者:钱宝坤

标准参考

根据现行 CSS 2.1 规范描述,'display' 特性用来决定元素所生成控制框的类型, 通常设置值为 'block'、'inline' 或 'none',全部值包括:

inline | block | list-item | run-in | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | none | inherit

关于 'display' 特性的详细信息,请参考 CSS2.1 规范 9.2.4 The 'display' property 中的内容。

但是,老旧的 CSS 1 规范中,'display' 特性值仅包括: block | inline | list-item | none

由此可见,两个时期的规范对 'display' 特性的值支持程度存在很大差异。

当 CSS 特性以及特性值出现书写错误,导致非法值或未知属性产生,客户端浏览器将必须忽略带有未知属性或非法值的样式声明。

具体信息可参考 CSS 2.1 规范: 4.2 Rules for handling parsing errors

这种情况在遵循 CSS 1 规范的浏览器中就可能会出现,那些在 CSS 1 中没有定义的 'display' 设定值会被当做非法值对待,因而遭到浏览器忽略。

问题描述

因 IE6 IE7 IE8(Q) 中遵循老旧的 CSS 1 规范,当 ‘display’ 特性设定值为非 'inline'、'block'、'none'、'inline-block'、'list-item' 时,'display' 特性设置将遭到忽略。

Opera 不支持非 CAPTION 元素的 'display:table-caption' 特性值设置,Firefox 不支持 'display:run-in' 设置,这些特性值设置也均将遭到忽略。

造成的影响

设置不被支持的 'display' 值,不仅不会达到预期效果,严重情况下的还会大面积影响布局。

受影响的浏览器

所有浏览器  

问题分析

'display' 特性的值,伴随着 CSS 规范诞生以来,一直在不断的补充。规范的修订与各个厂商的浏览器开发时段并行,这就导致了不同时段,不同厂商的不同版本浏览器对此特性值支持程度存在差异。我们构造以下代码来检测现阶段 'display' 特性值的支持情况:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<style>
div { font:'Tahoma,14px/2';border:5px solid gray;margin:10px;}
</style>
<script>
window.onload=function(){
  function getDisplayValues(){
    return {
      'inline':'inline',
      'block':'block',
      'table':'table',
      'inline-table':'inline-table',
      'table-row-group':'table-row-group',
      'table-header-group':'table-header-group',
      'table-footer-group':'table-footer-group',
      'table-row':'table-row',
      'table-column-group':'table-column-group',
      'table-column':'table-column',
      'table-cell':'table-cell',
      'table-caption':'table-caption',
      'none':'none',
      'list-item':'list-item',
      'run-in':'run-in',
      'inline-block':'inline-block',
      'inherit':'inherit'
    }
  }
  function getHTMLElement(tagName){
    return document.createElement(tagName);
  }
  function patchComputedStyle(){
    if(!window.getComputedStyle){
      window.getComputedStyle=function($target){
        return $target.currentStyle;
      };
    }
  }
  function setDisplayStyleValue(element,value){
    try{
      element.style['display'] = value;
    }catch(e){
      return ;
    }
  }
  function setElementText(element,setValue,computedValue){
    element.appendChild(
      document.createTextNode(
        'Setting Value is: $setValue , Computed display style value is : $computedValue'
        .replace(/\$setValue/,setValue)
        .replace(/\$computedValue/,computedValue)
    ));
    if (detectorInherit(setValue)){
      setValue = getComputedStyle(element.parentNode,null).display;
    }

    element.style['background'] = (setValue === computedValue) ? '' : 'red';

  }
  function appendElement(parentElement,childElement){
    parentElement.appendChild(childElement);
  }

  function buildElement(key,value){
    var divElement = getHTMLElement('div');
    setDisplayStyleValue(divElement,value);
    appendElement(document.body,divElement);
    setElementText(divElement,value, getComputedStyle(divElement,null).display);
    divElement = null;
  }
  function buildElementOfInherit(key,value){
    var parentDivElement = getHTMLElement('div'),
    childDivElement = getHTMLElement('div');
    setDisplayStyleValue(parentDivElement,'inline');
    setDisplayStyleValue(childDivElement,value);
    appendElement(parentDivElement,childDivElement);
    appendElement(document.body,parentDivElement);
    setElementText(childDivElement,value, getComputedStyle(childDivElement,null).display);
    parentDivElement = null;
    childDivElement = null;
  }

  function detectorInherit(value){
    return 'inherit' === value;
  }
  function buildTest(){
    var displayValues = getDisplayValues();
    for (var key in displayValues){
      if (detectorInherit(displayValues[key]))
        buildElementOfInherit(key,displayValues[key]);
      else
        buildElement(key,displayValues[key]);
    }
  }
  patchComputedStyle();
  buildTest();
}
</script>
</head>
<body>
</body>
</html>

代码中依次创建 DIV 标记,并赋予各个 'display' 值,通过得到计算后 'display' 样式值与设置值比较是否一致的方式,来确定各个浏览器是否支持某个 'display' 特性值。

各浏览器支持情况如下:

display IE6 IE7 IE8(Q) IE8(S) Firefox Chrome Safari Opera
inline Y Y Y Y Y Y Y Y
block Y Y Y Y Y Y Y Y
table N1 N1 N1 Y Y Y Y Y
inline-table N1 N1 N1 Y Y Y Y Y
table-caption N1 N1 N1 Y Y Y Y N6
table-cell N1 N1 N1 Y Y Y Y Y
table-row-group N1 N1 N1 Y Y Y Y Y
table-row N1 N1 N1 Y Y Y Y Y
table-header-group N2 N2 N2 Y Y Y Y Y
table-footer-group N2 N2 N2 Y Y Y Y Y
list-item Y3 Y3 Y3 Y Y Y Y Y
run-in N N N Y N Y Y Y
inline-block N4 N4 N4 Y Y Y Y Y
inherit N N N Y5 Y Y Y Y
none Y Y Y Y Y Y Y Y

【注】:设置 'display:none' 特性值的元素在所有浏览器中均不可视,说明均没有被渲染,样式设置有效。

【注】:表中蓝色背景文字表示浏览器对某特性设置支持,但存在实际表现不同于现行 CSS 2.1 规范描述,或存在浏览器厂商文档,已明表示与规范内同名属性作用不同的情况。

综合上表可知,'display' 设置值 'inline'、'block'、'list-item'、'none' 在所有浏览器中均被支持(恰好是 CSS 1 规范定义的全部 'display' 特性可选值)。

对于其他特性值,仅用以上测试代码无法将细节差异体现,本文中针对各种差异追加如下说明:

  • 【差异】1:IE6 IE7 IE8(Q) 中,尽管 TABLE 以及隶属于表格的相关元素布局效果与其他浏览器无明显差异;但是他们的默认 'display' 特性计算值均为 'block' ,为其他标记设置表格相关的 'display' 特性值:'table', 'inline-table', 'table-row-group', 'table-column', 'table-column-group','table-row', 'table-cell', 'table-caption' 均无效。
  • 【差异】2: IE6 IE7 IE8(Q) 中,可以为元素设置 'table-header-group'、'table-footer-group' 值不会产生异常,并且样式计算值也为 'table-header-group'、'table-footer-group',说明设置有效。但是,需要注意这些浏览器内 'table-header-group' 与 'table-footer-group' 样式默认作用的元素 THEARD 和 TFOOT ,他们默认 'display' 特性计算值却均为 'block'。
    另外,由于 HTML 4.01 规范内对 TABLE 标记的嵌套规则约束(<!ELEMENT TABLE - - (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)>),加上 TABLE 显示有关的 'table', 'inline-table', 'table-row-group', 'table-column', 'table-column-group','table-row', 'table-cell', 'table-caption' 样式特性不被支持。
    因此,如在 TABLE 标签内使用违反嵌套规则的标记,均会触发浏览器修复机制将错误嵌套修正,这会导致 'table-header-group'、'table-footer-group' 特性值设置无法被完全验证是有效的。
  • 【差异】3: IE6 IE7 IE8(Q) 中,LI 元素的默认 'display' 特性值为 'block' 不是 'list-item',但他们的显示效果一致。IE8(S) 中已经解决这个问题,LI 元素的默认 'display' 特性值恢复为 'list-item'。
  • 【差异】4:IE6 IE7 IE8(Q) 中,'display:inline-block' 特性值含义与 CSS 2.1 规范描述不同。对照 MSDN 描述以及 CSS 1CSS 2 历史规范,'display:inline-block' 最初由 IE 5.5 开始支持,直至 CSS 2.1 规范中才加入了此特性值。因此在这些古老版本 IE 浏览器中,'display:inline-block' 特性值设置不能将块元素转变为行内块,他的作用为触发 IE 的 hasLayout 特性,使元素拥有布局特性。
    如果将他用在行内元素上,可以使行内元素拥有布局,以便使宽高等无法作用在行内元素上的样式特性生效。对于块元素,他仅触发了布局特性,还要将块元素的 'display' 特性值设定为 'inline' 才可以获得类似规范描述的 'inline-block' 布局效果。
  • 【差异】5:IE8(S) 中,不支持用户使用 'display:inherit' 特性值继承 inline 元素的默认 'display' 值。
    详细情况可以参考本站文章:RA8001:IE6 IE7 IE8(Q) 不支持 CSS 特性的 'inherit' 值及 IE8(S) Opera 对此特性值的支持缺陷
  • 【差异】6:Opera 中,'display:table-caption' 特性值不能被设置,但 CAPTION 元素的默认 'display' 值为 'display:table-caption'。

【注】:由于各版本 IE 浏览器开发时间跨越了 CSS 1.0 规范标准现行与 CSS 2.1 规范标准制定时段,使得这些浏览器支持 CSS 1 规范至 CSS 2.1 规范内的全部或部分内容,从而导致了特性值支持的上的不同差异。

解决方案

尽量仅使用所有浏览器都支持的 'display' 特性值:'inline'、'block'、'list-item'、'none'。在 IE6 IE7 IE8(Q) 中实现块元素的 'display:inline-block' 特性值支持,需要先将块元素设置为行内元素,并设置可以在 IE6 IE7 IE8(Q) 内触发 haslayout 特性的专有特性 'zoom:1'。行内元素实现 'display:inline-block' 特性值支持只需直接设置此特性值或同样使用 'zoom:1' 即可。

参见

知识库

  • ...

相关问题

测试环境

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

关键字

display inline block list-item run-in inline-block table inline-table table-row-group table-header-group table-footer-group table-row table-column-group table-column table-cell table-caption none inherit