打印

RE1011: 各浏览器对于自动表格布局下未明确设定宽度的单元格的计算宽度存在差异

作者:陆远

标准参考

根据 CSS2.1 规范中的描述,当 'table-layout' 特性的计算值为 'auto' (初始值) 时代表表格将采用自动表格布局。列的宽度由以下条目决定:(仅列举与本文有关内容)

  1. 计算每一个单元格的最小内容宽度 (MCW):格式化过的内容可能会扩展到若干行,但不得溢出单元格框。若单元格指定的 'width' (W) 大于 MCW,W 作为最小单元格宽度。值 'auto' 代表 MCW 即最小单元格宽度。
    此外,计算每一个单元格的 "最大" 单元格宽度:除非发生明确换行,内容将不换行地进行格式化。
  2. 对于每一列,由只占该列的单元格确定一个最大和最小列宽。最小值为拥有最大的最小单元格宽度的那个单元格的宽度 (或者是列的 'width',取较大者)。最大值为最大的最大单元格宽度的那个单元格的宽度 (或者是列的 'width',取较大者)。

得到了每一列的最大和最小宽度后,列的宽度如下列所述影响最终表格的宽度:(仅列举与本文有关内容)

若 'table' 或者 'inline-table' 元素的 'width' 特性拥有明确的计算值 (W) 而不是 'auto',则特性的值为 "W" 与 "所有的列要求的最小宽度之和加上单元格间距或边框 (MIN)" 这两个值中的较大者。若 W 大于 MIN,多余的宽度应被分配到各列中。

关于 自动表格布局 的更多信息,请参考 CSS2.1 规范 17.5.2.2 Automatic table layout

问题描述

若表格内各列没有明确设定宽度,即其 'width' 特性为默认的 'auto',表格最终渲染时各列的计算宽度会由于单元格内容的差异在不同浏览器中出现不同的计算后的列宽。

造成的影响

此问题可能导致表格的列宽在不同浏览器中出现非常大的差异,严重情况下可能影响页面整体布局。

受影响的浏览器

所有浏览器  

问题分析

分析以下代码:td_width_auto.html

<!DOCTYPE html>
<html>
<head>
<style>
  * { margin:0; font:18px/2 'Trebuchet MS'; }
  .info td { text-align:center; }
  table { width:300px; }
</style>
<script>
  function $(id) { return document.getElementById(id); }

  window.onload = function () {
    for (var k = 1; k <= 3; k++) {
      for (var i = 1; i <= 4; i++) {
        $('c' + k + i + 'i').innerHTML = $('c' + k + i).offsetWidth;
        $('c' + k + i + 'i').width = $('c' + k + i).offsetWidth;
      }
    }
  }
</script>
</head>
<body>
<table cellpadding="0" cellspacing="0">
  <tr>
    <td id="c11" style="background:palegreen;"><div style="width:100px;">DIV 100px</div></td>
    <td id="c12" style="background:goldenrod;">
      <div style="float:left; width:20px; height:20px; background:#ccc;"></div>
      <div style="float:left; width:20px; height:20px; background:#bbb;"></div>
      <div style="float:left; width:20px; height:20px; background:#aaa;"></div>
    </td>
    <td id="c13" style="background:palegreen;"><div style="width:100px;">DIV 100px</div></td>
    <td id="c14" style="background:goldenrod;">
      <div style="float:left; width:20px; height:20px; background:#ccc;"></div>
      <div style="float:left; width:20px; height:20px; background:#bbb;"></div>
      <div style="float:left; width:20px; height:20px; background:#aaa;"></div>
      <div style="float:left; width:20px; height:20px; background:#999;"></div>
      <div style="float:left; width:20px; height:20px; background:#888;"></div>
    </td>
  </tr>
</table>
<table class="info" cellpadding="0" cellspacing="0">
  <tr>
    <td id="c11i"></td>
    <td id="c12i"></td>
    <td id="c13i"></td>
    <td id="c14i"></td>
  </tr>
</table>
<table cellpadding="0" cellspacing="0">
  <tr>
    <td id="c21" style="background:palegreen;"><div style="width:100px;">DIV 100px</div></td>
    <td id="c22" style="background:goldenrod;">
      <div style="float:left; width:30px; height:20px; background:#ccc;"></div>
      <div style="float:left; width:30px; height:20px; background:#bbb;"></div>
    </td>
    <td id="c23" style="background:palegreen;"><div style="width:100px;">DIV 100px</div></td>
    <td id="c24" style="background:goldenrod;">
      <div style="float:left; width:30px; height:20px; background:#ccc;"></div>
      <div style="float:left; width:40px; height:20px; background:#bbb;"></div>
      <div style="float:left; width:30px; height:20px; background:#aaa;"></div>
    </td>
  </tr>
</table>
<table class="info" cellpadding="0" cellspacing="0">
  <tr>
    <td id="c21i"></td>
    <td id="c22i"></td>
    <td id="c23i"></td>
    <td id="c24i"></td>
  </tr>
</table>
<table cellpadding="0" cellspacing="0">
  <tr>
    <td id="c31" style="background:palegreen;"><div style="width:100px;">DIV 100px</div></td>
    <td id="c32" style="background:goldenrod;">
      <div style="float:left; width:20px; height:20px; background:#ccc;"></div>
      <div style="float:left; width:20px; height:20px; background:#bbb;"></div>
      <div style="float:left; width:20px; height:20px; background:#aaa;"></div>
      <div style="float:left; width:20px; height:20px; background:#999;"></div>
      <div style="float:left; width:20px; height:20px; background:#888;"></div>
      <div style="float:left; width:20px; height:20px; background:#777;"></div>
    </td>
    <td id="c33" style="background:palegreen;"><div style="width:100px;">DIV 100px</div></td>
    <td id="c34" style="background:goldenrod;">
      <div style="float:left; width:20px; height:20px; background:#ccc;"></div>
      <div style="float:left; width:20px; height:20px; background:#bbb;"></div>
      <div style="float:left; width:20px; height:20px; background:#aaa;"></div>
      <div style="float:left; width:20px; height:20px; background:#999;"></div>
      <div style="float:left; width:20px; height:20px; background:#888;"></div>
      <div style="float:left; width:20px; height:20px; background:#777;"></div>
    </td>
  </tr>
</table>
<table class="info" cellpadding="0" cellspacing="0">
  <tr>
    <td id="c31i"></td>
    <td id="c32i"></td>
    <td id="c33i"></td>
    <td id="c34i"></td>
  </tr>
</table>
</body>
</html>

上述代码中 3 组表格结构相似,均为 4 列没有设定宽度的 TD 元素,第 1、3 列的 TD 中包含一个宽度 100px 的 DIV 元素,第 2、4 列的 TD 中包含若干宽度较小的浮动元素。

这段代码在不同浏览器中运行结果如下:

IE6 IE7 IE8 Firefox Opera Chrome Safari

可见,各浏览器之间对于此种情形下的列的宽度计算存在算法差异。

尤其在第 3 组中,第 2、4 列中的内容完全相同,在 IE6 IE7 IE8 Firefox Opera 中,浏览器平均分配了列宽。而在 Chrome Safari 中,则出于浏览器内部某种算法而使得列的最终计算宽度与其他浏览器出现了非常大的差异。

下面根据第 3 组表格的数据,参照 CSS2.1 规范来计算列的宽度:

  第一列 第二列 第三列 第四列
最小列宽 100px 20px 100px 20px
最大列宽 100px 120px 100px 120px
表格宽度 (W) 300px
所有的列要求的最小宽度之和加上单元格间距或边框 (MIN) 240px
表格最终宽度 max(300px, 240px) = 300px
多余的宽度应被分配到各列中

而 CSS2.1 规范并没有明确说明多余宽度的分配算法,所以这里不同浏览器之间出现了差异。

解决方案

在表格布局中应明确的为各列设定一个明确的宽度。

参见

知识库

相关问题

测试环境

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

关键字

TABLE TR 表格 列 width 宽度 auto